# Dousen > Dousen is the automation framework for game assets. It connects Jira Cloud, Perforce, DCC tools (Blender, Maya, 3ds Max, Houdini, Substance Painter, Substance Designer) and Unreal Engine 5.7/5.8. An artist picks a Jira task in the DousenDesktop app (Windows); Dousen opens one Perforce changelist for that task, validates assets against the project's naming conventions and rules inside the DCC before export, publishes FBX and textures to Unreal Engine through the DousenUE plugin (Interchange import), and can move the Jira issue to the next status when the changelist is submitted. Made for technical artists and art teams at small and mid-size game studios (indie and AA). Server (DousenCore) hosted at dousen.io or self-hosted with Docker Compose on Linux with a Dousen license. Free during the studio beta; access by request. Built by Luca Vitiello, a technical artist with ten years in AAA game development. This file contains the full text of every public page on dousen.io, for AI assistants and crawlers. Each page starts with its title, canonical URL and summary. Generated by scripts/build-llms-full.py. # Product ## Dousen — The automation framework for game assets URL: https://dousen.io/ Summary: Dousen connects Jira, Perforce, your DCCs, and Unreal Engine. Validate and publish assets from the DCC, import them into Unreal, and move the Jira ticket when the changelist is submitted. //dousen/main — for Jira + Perforce studios free studio beta # The automation framework for game assets. Batteries included. Dousen connects Jira, Perforce, your DCCs, and Unreal Engine. Artists publish from the DCC. Dousen validates the asset, imports it into Unreal, and moves the Jira ticket when the changelist is submitted. Request early access Quick start Free during the studio beta, and free forever for teams of up to 5 users. pipeline.log live 17:21:08desktopchangelistCL 28471 opened for HBR-142 17:32:40mayacollect3 instances · SM_CargoCrate_01 checked 17:32:41dousenvalidatenaming ✓  transforms ✓  poly count ✓ 17:32:43dousenexportSM_CargoCrate_01.fbx → bridge → unreal 17:32:47unrealimport/Game/Props/Cargo/SM_CargoCrate_01 · saved 17:32:47desktophistorySM_CargoCrate_01 · Imported 17:48:02perforcesubmitCL 28471 submitted 17:48:03jiratransitionHBR-142 · In Progress → In Review The log follows one asset from a Jira task to a submitted changelist. The changelist opens from the task, the checked instance is validated and exported, Unreal imports and saves it, and the Jira ticket moves when the changelist is submitted. ships with addons for blender maya houdini 3ds_max substance_painter substance_designer unreal_engine_5 //dousen/features ## What Dousen automates Dousen runs when artists save, publish, or submit a changelist, and handles the changelists, validation, Unreal imports, and Jira updates around those steps. on_save ### Publish from the DCC The Dousen panel in Blender, Maya, 3ds Max, and Substance collects the publishable objects in your scene as instances. Check the ones you want and click Publish. Houdini publishes from shelf tools. In Blender, Maya, 3ds Max, and Substance Painter, turn on publish-on-save to publish the checked instances each time you save. It doesn’t run the full validation. SM_CargoCrate_01 ✓  SM_CargoBarrel_01 ✓  SM_CargoPallet_01 — pre_export ### Validation before export Naming conventions and validators are set per project and per asset type in the web portal. A misnamed mesh or an unfrozen transform is caught in the DCC before export. In Maya and 3ds Max, Select Invalid selects the failing objects, and Repair fixes them where a validator supports it. static_mesh · SM + CargoCrate + 01 → SM_CargoCrate_01 ✓ on_publish ### Import and save in Unreal The export (FBX, or textures from Substance) goes over the local bridge to the Unreal editor connected to the same project, or to a background import if no editor is open and headless import is on. Unreal imports it to the path your conventions define and saves it. Publish history in DousenDesktop shows each instance as imported, failed, or unconfirmed. SM_CargoCrate_01.fbx → /Game/Props/Cargo/SM_CargoCrate_01 on_submit ### Changelists and Jira transitions Every changelist opens from a Jira task in DousenDesktop. File locks and checkouts show in the DCC’s Perforce tab. When you submit the changelist, Dousen runs the Jira transition configured for the project. CL 28471 submitted → HBR-142 In Review //dousen/product ## The desktop app and the DCC panel DousenDesktop runs in the tray with your Jira tasks, changelists, and app launchers. The Dousen panel inside each DCC handles validation and publishing. Screenshots use a sample project. //dousen/unreal ## Import settings in Unreal Dousen imports with Unreal’s Interchange framework. The import settings come from the project conventions and are saved with the asset, so a reimport replays them. import_profile ### Named import profiles A profile in the project conventions sets mesh import options such as `nanite`, `collision`, `normals`, `tangents`, `import_lods`, and `uniform_scale`. Tag an instance with `import_profile` and Dousen imports it with those settings. instance_manifest ### Reimport keeps existing members On reimport, the existing members of a multi-mesh instance keep their asset paths and settings. New members aren’t imported until you approve them with Review instance topology in the Content Browser. Removed members stay in the project. project_stack ### Opt-in stack for manual imports To use your conventions for manual imports too, install a project stack with the `Dousen.InstallImportStack` console command. You can then select the stack in the Content Browser import dialog. Installing a stack doesn’t change any Content Browser default. Read the Interchange guide → //dousen/setup ## Set up one project, then roll it out 01 ### Configure the project in the portal Create the project, connect Jira and Perforce, and set the naming conventions and validators for each asset type. Run Dousen in the cloud or self-hosted. 02 ### Prepare one workstation Install DousenDesktop and run the setup wizard, then sign in. The wizard can create the Perforce workspace, find your DCCs, and check the Unreal project you select for the plugin. The DCC addons are bundled with the installer. 03 ### Publish a test asset Publish one small instance and check that Unreal saved it. Then install DousenDesktop on the other workstations. Conventions and validators come from the server. Follow the quick start → Project admin guides Naming conventions Asset validation Separate source repositories Studio tools and startup scripts Self-hosted install //dousen/docs ## Guides by role artists ### Publishing assets Instances, validation, Publish history, and retrying a failed publish. Publishing guide → unreal / tech art ### Unreal Interchange Import profiles, reimport, Review instance topology, and project stacks. Interchange guide → project admins ### Settings reference Project settings, conventions, validators, and deployment options. Settings reference → //dousen/early-access ## Request early access Dousen is in free beta for pilot studios, and stays free forever for teams of up to 5 users. Tell us about your team and the DCCs you run, or email hello@dousen.io, and we’ll set your studio up. Request early access Download DousenDesktop ## About Dousen — Dousen URL: https://dousen.io/about.html Summary: Dousen is the automation framework for game assets, built by technical artist Luca Vitiello. What it is, who makes it, and how to get in touch. Updated 6 October 2026 Dousen automates the game asset path between Jira Cloud, Perforce, the DCC apps artists already use, and Unreal Engine 5.7 and 5.8. An artist picks a task, Dousen opens the changelist, checks the asset before export, imports it into Unreal and moves the ticket on submit. It is built by Luca Vitiello, a technical artist with ten years in AAA game development. ## Why it exists Every studio of a certain size ends up writing the same tools: a naming checker in each DCC, a script that opens a changelist for the current ticket, an exporter that puts files in the right Unreal folder, a hook that moves the ticket when the change is submitted. Those tools are rebuilt from scratch at every studio, and small teams never get around to them. Dousen is that tool set, built once and configured per project in YAML, so an indie or AA studio gets the pipeline discipline of a large one without a tools team. ## What Dousen is Dousen is three pieces that work together: - DousenDesktop, a Windows app that lists your Jira tasks, opens one Perforce changelist per task, launches your DCCs, and relays events between them and Unreal. - DCC addons for Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer that validate assets against the project's naming conventions and rules, show Perforce file locks, and publish FBX, textures and Houdini HDA, VAT and Alembic exports. - DousenCore, the studio server with a web portal for projects, conventions and validators, plus the DousenUE plugin that imports published assets into Unreal Engine 5.7 and 5.8 through Interchange. Dousen doesn't replace Jira, Perforce or Unreal. It drives them. See the documentation for what runs where. ## Who makes it Dousen is made by Luca Vitiello (https://technicalart.it/), a technical artist with ten years in AAA game development, including technical artist roles at Rockstar Games, Splash Damage and Ubisoft. At those studios he built the internal versions of what Dousen does: naming enforcement in the DCC, changelist automation tied to the task tracker, and automated engine imports. He also teaches game development at university level. Dousen is developed in Italy and sold worldwide. The company details are in the terms of service. ## Where it is today - Dousen is free during the studio beta, with access by request, and stays free forever for teams of up to 5 users. Pricing for larger teams has not been announced. Request early access. - The desktop app runs on Windows 10 and 11. The server runs hosted at dousen.io or self-hosted with Docker Compose on Linux. See Self-hosted install. - Supported engines: Unreal Engine 5.7 and 5.8. ## If Dousen goes away Your assets, changelists and tasks already live in your Perforce depot, your Unreal project and Jira, because Dousen drives those tools and doesn't hold them. Naming conventions are one YAML document that you edit in the portal, so you can copy it out and keep it. Self-hosting runs the Dousen server on your own Linux host with Docker Compose, and needs a Dousen license. See Self-hosted install. ## Contact Email hello@dousen.io. For AI assistants and crawlers, a plain-text summary of the product and all pages is at llms.txt and llms-full.txt. ## Download — Dousen URL: https://dousen.io/download.html Summary: Download the Dousen desktop app for Windows. The automation framework for game assets. //dousen/download # Get the desktop app. The automation framework for game assets — connects your DCCs, Perforce, and Jira in one app. ## Dousen for Windows Windows 10 / 11 · 64-bit Sign in with your Dousen account to download. Sign in & download Your download should start shortly. Restart download if it doesn't. NSIS installer · ~85 MB ### What's included - Desktop System tray app, DCC launcher, pipeline panel - DCC addons Blender, Maya, Houdini, 3ds Max, Substance Painter, Substance Designer - UE5 plugin Bundled — copy to your project's Plugins folder - Setup First-run wizard walks you through server, Jira, and Perforce config macOS and Linux builds are not available yet. Let us know if you need them. ## Get Early Access — Dousen URL: https://dousen.io/early-access.html Summary: Join the Dousen early access programme. Get set up in under 15 minutes. //dousen/early-access # Let's set up your studio. Dousen is in early access. Drop us an email and we'll have you running in under 15 minutes — no DevOps required. - 1 Send us an email — tell us your studio name, team size, and which DCC tools you use (Blender, Maya, UE5…). - 2 We provision your instance — we'll reply within 24 hours with your credentials and a short onboarding call if you want one. - 3 Connect your tools — install the desktop app and DCC addons. Your first Jira task syncs in minutes. Contact us at hello@dousen.io We read every email and respond personally — no automated replies. Privacy Policy · Terms of Service ← Back to home # Guides ## One Perforce changelist per Jira task — Dousen URL: https://dousen.io/guides/changelist-per-jira-task.html Summary: How Dousen opens a numbered Perforce changelist for the selected Jira issue, keeps the Jira key in the description, and moves the issue when you submit. By Luca Vitiello · Updated 6 October 2026 Dousen opens a numbered Perforce changelist for the Jira issue you select, writes the Jira key and two marker lines into its description, and sends the task and changelist to every DCC panel. Exports land in that changelist. When you submit, DousenCore can run a Jira workflow transition for the issue. - Open changelist creates a numbered changelist with `p4 change -i`, or reuses the task's open one. - The description holds the Jira key and two marker lines, `[Dousen:]` and `[DousenProject: Task:]`. - Submit needs a message of at least 5 characters and fails if the changelist has no opened files. - `jira.on_submit_transition` names the Jira workflow transition to run after a successful submit. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## Why one changelist per task? A changelist that maps to a single task is easy to review, because the reviewer sees exactly the files that one ticket changed. It also makes bisecting practical. When a build breaks, you can step through submitted changelists and each step is one piece of work, not a mix of three. And when the Jira key sits in the changelist description, `p4 changes` and the depot's submitted history answer "which ticket changed this file" without opening Jira. The cost is discipline. Artists have to open the right changelist, keep unrelated files out of it, and write a description that carries the key. Dousen does those parts for you. ## How does Dousen open a changelist for a Jira issue? - In DousenDesktop, open the My tasks tab and select the issue. The list comes straight from Jira Cloud with your own email and API token. - Click Open changelist. Desktop creates a numbered changelist in your workspace with `p4 change -i`, under your own Perforce user, and reports the number to DousenCore, which stores it under the issue key. - If the task already has an open changelist, Desktop reuses it instead of creating a duplicate. The task's detail pane shows the linked changelist (CL). ## What does the changelist description contain? Every changelist that Desktop opens carries the Jira key and two marker lines. The first holds DousenCore's id for the changelist, not the Perforce number. The second holds the project id and the Jira key. While the changelist is open, the description looks like this: ``` DOU-142 [Dousen:3f6c1a52-8e0b-4d7e-9a14-2b7d5c0e91aa] [DousenProject:7b2e4c10-5d38-4f0a-b6c9-1e83a7d2f405 Task:DOU-142] ``` After you submit, your message comes first, followed by the same two marker lines, so the Jira key stays in the depot's submitted history. Dousen also uses the markers to find a changelist again after a lost reply, so a retry doesn't create a duplicate. The exact format is in Changelist descriptions. ## How do the DCCs and exports pick up the changelist? While the task stays selected, every DCC addon receives the task and changelist through the `task.context` bridge event. Launch the DCC from DousenDesktop and its Dousen panel shows the same task and changelist. Exports from any addon go to that changelist, and checkout and add in the panel use it too. If no task is active, they fall back to Perforce's default changelist, so select the task before you work. See DCC addons and Jira tasks. ## How does submit work? - Check that the changelist holds the exported files, sidecars and changed Unreal packages the task needs. The submit fails if the numbered changelist has no opened files, and Desktop never moves files out of the default changelist, so move them in with P4V first. - Click Submit changes in the task's detail pane. - In the Submit Changelist dialog, enter a message of at least 5 characters and click Submit changes. - Desktop sets the description, runs `p4 submit -c ` and reports the result to DousenCore. A confirmed publish doesn't mean the changelist was submitted. Check the submitted changelist in Perforce afterwards. A project with a separate source-art repository gets one changelist per Perforce server, and the Jira transition waits until every non-empty changelist for the task is submitted. See Source repositories. ## How does Dousen move the Jira issue on submit? A project admin connects Jira for the project in the web portal (Project settings, Jira Configuration) and sets `jira.on_submit_transition`, shown as Jira transition on CL submit under Integrations in Pipeline settings: ``` jira: on_submit_transition: "In Review" ``` After a successful submit, DousenCore lists the issue's transitions, picks the one whose name matches the setting, ignoring case, and runs it. Enter the name of the workflow transition, which can differ from the status it leads to. A transition called "Send to Review" can lead to a status called "In Review", and you would enter the transition name. If no transition matches or Jira returns an error, the submit still succeeds, the issue doesn't move, and DousenCore logs the problem. Saving or publishing an asset never changes the issue. Details are in Transition the issue on submit. ## Related - Perforce and Jira tasks in the documentation - Perforce in Blender - Unreal asset naming conventions Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Guides for game art pipelines with Perforce, Jira and Unreal — Dousen URL: https://dousen.io/guides/index.html Summary: Practical guides for game art teams: Perforce in Blender, Maya, 3ds Max, Houdini and Substance, one changelist per Jira task, Unreal naming and FBX checks. By Luca Vitiello · Updated 6 October 2026 These guides show how game art teams use Dousen with Perforce, Jira Cloud and Unreal Engine 5.7 and 5.8: checking out and locking files from Blender, Maya, 3ds Max, Houdini and Substance, keeping one changelist per Jira task, naming Unreal assets, and checking an FBX before import. One changelist per Jira task One Perforce changelist per Jira task, with the issue moved on submit Unreal Engine asset naming conventions Prefix reference for Unreal Engine assets and how to enforce it Validate an FBX before Unreal import What to check in an FBX before Unreal imports it Perforce in Blender Check out, lock, sync and submit from the Dousen sidebar Perforce in Maya Check out, lock, sync and submit from the Dousen panel Perforce in 3ds Max Check out, lock, sync and submit from the Dousen panel Perforce in Houdini What the Dousen shelf tools do for Perforce, and what they don't Perforce in Substance Painter and Designer Check out, lock, sync and submit from the Dousen dock ## Related documentation - Quick start - DCC addons - Perforce Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce in 3ds Max: check out, lock, sync and submit from the Dousen panel — Dousen URL: https://dousen.io/guides/perforce-in-3ds-max.html Summary: How the Dousen panel in 3ds Max shows Perforce lock status, checks out, syncs and reverts the scene, and keeps exported FBX files in the Jira task changelist. By Luca Vitiello · Updated 6 October 2026 Dousen adds a docked panel to 3ds Max. Its Perforce tab shows whether the open scene is locked, opened by others or behind the depot, and lets you check out, sync and revert it under your own Perforce user. Published exports go to the Jira task's changelist. - 3ds Max opens the same docked panel as Maya at startup, with a Perforce tab. - The Dousen menu (3ds Max 2025 and later) opens it. - Buttons: Check Out, Sync & Reload, Revert, Refresh. - Status comes from `p4 fstat` and refreshes about every 30 seconds. - An animation instance exports its own nodes and skeleton roots to FBX, like a mesh instance. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## What Perforce status does the Dousen panel show in 3ds Max? 3ds Max opens the same docked panel as Maya at startup, with the same tabs. In 3ds Max 2025 and later, a Dousen menu appears before the Help menu, and Dousen Panel shows or hides the dock. The Perforce tab shows the state of the current scene, read with `p4 fstat` and refreshed about every 30 seconds. The panel header shows the current task and Stream: or Classic depot. The lines are: | Status | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock, from an exclusive checkout or `p4 lock`. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open or locked, and your copy is current. | | P4 error: or Not in Perforce | Perforce can't answer, because the server is unreachable or the file isn't in the depot. | ## How do I check out, sync and revert a scene from 3ds Max? - Open a scene saved under your Perforce workspace root and select the Perforce tab. - Click Check Out to edit an existing file. It opens in the selected task's changelist, or in `default` if no task is active. - If the status says Not at latest, click Sync & Reload and confirm. The reload discards unsaved changes. - Click Revert and confirm to discard your changes to an open file. - Click Refresh to read the state again. Each button is available only when it applies to the file's state. For a new scene, use the New Asset tab, or New Asset in the Dousen menu, and click Set Up Asset. Dousen saves the scene to the resolved source path and adds it to the task's changelist. ## How do exported files land in the task's changelist? Select a task in DousenDesktop and it sends the Jira key and changelist to every running DCC. On the Publish tab, click Publish. Dousen selects each instance's nodes, plus the skeleton root bones for a skinned mesh, exports them as FBX, and opens the scene and your previous outputs for edit in the task's changelist. New files are added after the export. Nothing is submitted until you submit from DousenDesktop, as described in One changelist per Jira task. The Publish mesh.export on save checkbox on the Tools tab applies the same handling on save. After you restart 3ds Max, the first publish doesn't know the previous outputs. Check those out yourself if your workspace is read-only. ## What stops a publish in 3ds Max? A Perforce pre-flight runs before the export. If another user has locked a file the export would write, the publish stops and names the lock, and the failure shows in Publish history in DousenDesktop. Save-triggered publishes check for locks as well. ## How does the 3ds Max addon load? DousenDesktop ships the addon and loads it when you launch 3ds Max from the apps bar. Check the executable path under Settings → DCC Apps first. The panel opens at startup. A 3ds Max started from a desktop shortcut has no Dousen panel, and a running session needs a restart after you update Desktop. If your studio runs its own startup scripts, Loading studio tools explains when they run. See also How the addons load. If your studio keeps DCC source files in a separate Perforce repository, possibly on another server, the same buttons act on that repository's server. See Source repositories for the admin binding and the artist workspace. ## Related - 3ds Max addon reference - Perforce in the Dousen docs - One changelist per Jira task - Perforce actions in the DCC addons Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce in Blender: check out, lock, sync and submit from the Dousen sidebar — Dousen URL: https://dousen.io/guides/perforce-in-blender.html Summary: How the Dousen sidebar in Blender shows Perforce lock status, checks out, syncs and reverts the .blend file, and keeps exports in the Jira task changelist. By Luca Vitiello · Updated 6 October 2026 Dousen adds a Dousen tab to the Blender sidebar (N) with a File Status (P4) sub-panel. It shows whether the open .blend file is locked, opened by others or behind the depot, and lets you check out, sync and revert it under your own Perforce user. Published exports go to the Jira task's changelist. - The panel is the Dousen tab in the 3D Viewport sidebar (press N), with a File Status (P4) sub-panel. - Status comes from `p4 fstat` and refreshes about every 30 seconds. - Buttons: Check Out Source, Sync & Reload (not at latest), Revert Checkout, Refresh. - Checkout uses the selected Jira task's changelist, or `default` if no task is active. - Dousen runs `p4` under your own Perforce user and workspace. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## What Perforce status does the Dousen sidebar show in Blender? Press N over the 3D Viewport and select the Dousen tab. The File Status (P4) sub-panel starts collapsed. Expand it to see the lock state of the current `.blend` file. Dousen reads the state with `p4 fstat`, through P4Python if it's installed or the `p4` command line otherwise, and refreshes it about every 30 seconds. The line is one of these: | Status | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock, from an exclusive checkout or `p4 lock`. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open or locked, and your copy is current. | | P4 error: or Not in Perforce | Perforce can't answer, because the server is unreachable or the file isn't in the depot. | If your project uses Perforce streams, Dousen detects that on its own. The sidebar is a native Blender panel, so the stream name appears in the DousenDesktop status bar and in the Qt panels of other DCCs, not in Blender. ## How do I check out, sync and revert a file from Blender? Only the button that applies to the file's current state appears in File Status (P4). - Open a `.blend` file that is under your Perforce workspace root. - Expand File Status (P4) and read the status line. - Click Check Out Source to edit an existing file. The file opens for edit in the task's changelist, and the status changes to Locked by you if the checkout was exclusive. - If the status says Not at latest, click Sync & Reload (not at latest). Dousen asks you to confirm first, because the reload discards unsaved changes. - To drop your changes, click Revert Checkout and confirm. The scene matches the restored file afterward. - Click Refresh to read the lock state again without waiting for the timer. To add a new file, use Set Up Asset in the New Asset sub-panel. It saves the `.blend` file to the source path that your conventions resolve and adds it to the task's changelist. ## How do exported files land in the task's changelist? When you select a task in DousenDesktop, Desktop sends the Jira key and changelist to every running DCC. Click Publish Checked Instances and Dousen opens the scene and the files from your last export for edit in that changelist, then adds newly created files after the export. The publish itself doesn't submit anything. Submit the changelist from DousenDesktop afterward. The full flow is in One changelist per Jira task. Auto-publish on Save uses the same Perforce handling. If you restart Blender, the first publish afterward doesn't know the previous outputs. Check those out yourself if your workspace is read-only. ## What stops a publish in Blender? Before it exports, Dousen runs a Perforce pre-flight. If another user has locked a file that the export would write, the publish stops and names the lock. The failure appears in the Publish history tab in DousenDesktop. Coordinate with the person who holds the lock, or ask them to submit or revert. ## How does the Blender addon load? DousenDesktop ships the addon, so you don't install anything in Blender. Launch Blender from the apps bar in Desktop, after you check the executable path in Settings → DCC Apps. Desktop loads the addon and passes it the project, task and sign-in details. A Blender that you start from a desktop shortcut has no Dousen tab. After you update DousenDesktop, restart Blender so it loads the new addon code. The DCC addons page covers startup scripts and troubleshooting. If your studio keeps DCC source files in a separate Perforce repository, possibly on another server, the same buttons act on that repository's server. See Source repositories for the admin binding and the artist workspace. ## Related - Blender addon reference - Perforce in the Dousen docs - One changelist per Jira task - Perforce actions in the DCC addons Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce in Houdini: check out, lock, sync and submit from the Dousen shelf — Dousen URL: https://dousen.io/guides/perforce-in-houdini.html Summary: How the Dousen shelf in Houdini checks Perforce file status, checks out, syncs and reverts the scene, and keeps exports in the Jira task changelist. By Luca Vitiello · Updated 6 October 2026 Houdini has no Dousen panel. The Dousen shelf has Perforce tools to read file status, check out, sync and revert the open scene under your own Perforce user, and the HDA, VAT and Alembic export tools check for other users' locks first and use the Jira task's changelist. - Houdini has no Dousen panel. Perforce actions are tools on the Dousen shelf. - Tools: Dousen: File Status (P4), Dousen: Check Out, Dousen: Sync & Reload, Dousen: Revert Checkout. - The docs list no Refresh tool for Houdini; run Dousen: File Status (P4) again to re-read. - Dousen: Export HDA, Export VAT and Export Alembic run the Perforce pre-flight. - The export tools don't run validation; Dousen: Validate is manual. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## What Perforce status does Dousen show in Houdini? Houdini has no docked panel. The Perforce actions are four tools on the Dousen shelf: Dousen: File Status (P4), Dousen: Check Out, Dousen: Sync & Reload and Dousen: Revert Checkout. The Perforce docs say the Dousen integration in Houdini reports the same `p4 fstat` status as the other DCCs: Locked by (CL n), Opened by , Locked by you, Not at latest and Available, plus P4 error or Not in Perforce when Perforce can't answer. The docs don't describe a persistent status display in Houdini, a 30-second refresh there, or a Refresh button, so run Dousen: File Status (P4) when you want a current reading. The Perforce docs describe the stream label only for the Qt panels, so check the stream in the DousenDesktop status bar. ## How do I check out, sync and revert a Houdini scene? - Open a scene saved under your Perforce workspace root. - Click Dousen: File Status (P4) on the shelf and read the result. - Click Dousen: Check Out to edit an existing file. It opens in the selected Jira task's changelist, or in `default` if no task is active. - If the file isn't at the latest revision, click Dousen: Sync & Reload and confirm. The reload discards unsaved changes. - Click Dousen: Revert Checkout and confirm to discard your changes to an open file. Each action is available only when it applies to the file's state. The docs list no add tool and no new-asset setup for Houdini. Newly created export files are added to the changelist after an export. ## How do Houdini exports land in the task's changelist? DousenDesktop sends the selected task's Jira key and changelist to every running DCC. Dousen: Export HDA, Dousen: Export VAT and Dousen: Export Alembic then publish through that task context. Before each export Dousen opens the scene and the files from your last export for edit in the task's changelist, and it adds new files afterward. The same pre-flight applies to Houdini auto-publish. Dousen: Send to Unreal does the same as Dousen: Export VAT. Nothing is submitted by a publish. Submit from DousenDesktop, as described in One changelist per Jira task. Publish history in DousenDesktop doesn't list exports from the Houdini shelf tools. Use Show connection events there instead. After you restart Houdini, the first publish doesn't know the previous outputs, so check them out yourself if your workspace is read-only. ## What stops a publish in Houdini? If another user has locked a file that an export would write, the export tool stops and names the lock. The three export tools don't run validation, so that lock check is the only gate. Run Dousen: Validate yourself before you export. It prints results to the console and has no fix buttons. ## How does the Houdini addon load? You don't install the addon in Houdini. DousenDesktop ships it and loads it when you launch Houdini from the apps bar. Check the executable path under Settings → DCC Apps first. A Houdini started from a desktop shortcut has no Dousen shelf, and a running session needs a restart after you update Desktop. See How the addons load and the Houdini reference. If your studio keeps DCC source files in a separate Perforce repository, possibly on another server, the same buttons act on that repository's server. See Source repositories for the admin binding and the artist workspace. ## Related - Houdini addon reference - Perforce in the Dousen docs - One changelist per Jira task - Perforce actions in the DCC addons Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce in Maya: check out, lock, sync and submit from the Dousen panel — Dousen URL: https://dousen.io/guides/perforce-in-maya.html Summary: How the Dousen panel in Maya shows Perforce lock status, checks out, syncs and reverts the scene, and keeps exported FBX files in the Jira task changelist. By Luca Vitiello · Updated 6 October 2026 Dousen adds a docked panel and shelf to Maya. Its Perforce tab shows whether the open scene is locked, opened by others or behind the depot, and lets you check out, sync and revert it under your own Perforce user. Published exports go to the Jira task's changelist. - Maya starts with a Dousen shelf and a docked panel with the tabs Publish, Perforce, New Asset, Materials and Tools. - The Perforce tab shows live status from `p4 fstat`, refreshed about every 30 seconds. - Buttons: Check Out, Sync & Reload, Revert, Refresh. - New scenes from Set Up Asset are saved as `.ma` and added to the task's changelist. - The panel header shows the current task and the Perforce stream, or Classic depot. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## What Perforce status does the Dousen panel show in Maya? Maya starts with a Dousen shelf and a docked panel. Open the Perforce tab to see the state of the current scene file. Dousen reads it with `p4 fstat`, through P4Python if it's installed or the `p4` command line otherwise, and refreshes about every 30 seconds. Next to the file status the panel shows Stream: for a stream workspace, or Classic depot. The status line is one of these: | Status | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock, from an exclusive checkout or `p4 lock`. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open or locked, and your copy is current. | | P4 error: or Not in Perforce | Perforce can't answer, because the server is unreachable or the file isn't in the depot. | ## How do I check out, sync and revert a scene from Maya? Each button is available only when it applies to the file's current state. - Open a scene saved under your Perforce workspace root, then open the Perforce tab. - Click Check Out to edit an existing file. It opens in the changelist of the task selected in DousenDesktop, or in `default` if no task is active. - If the file is behind the depot, click Sync & Reload. Dousen asks you to confirm, because the reload discards unsaved changes. - Click Revert and confirm to discard your changes to an open file. The scene matches the restored file afterward. - Click Refresh to read the lock state again. For a new scene, open the New Asset tab, click Load Conventions, choose a name, type and taxonomy, and click Set Up Asset. Dousen saves the `.ma` file to the resolved source path and adds it to the task's changelist. The Dousen Asset shelf button opens a window that does the same. ## How do exported files land in the task's changelist? Desktop sends the Jira key and changelist to every running DCC when you select a task. When you click Publish on the Publish tab, Dousen opens the scene and the files from your last export for edit in that changelist and adds newly created files after the export. Each instance exports as its own FBX file. The publish doesn't submit anything, so submit the changelist from DousenDesktop afterward. One changelist per Jira task walks through that step. The Publish mesh.export on save checkbox on the Tools tab triggers the same handling on every save. After you restart Maya, the first publish doesn't know the previous outputs. Check those out yourself if your workspace is read-only. ## What stops a publish in Maya? Dousen runs a Perforce pre-flight before it exports. If another user has locked a file that the export would write, the publish stops and names the lock. A save-triggered publish stops the same way. Lock failures appear in Publish history in DousenDesktop. Ask the lock holder to submit or revert, then publish again. ## How does the Maya addon load? You don't install the addon in Maya. DousenDesktop ships it and loads it when you launch Maya from the apps bar, using the executable path in Settings → DCC Apps. The panel opens at startup, and the Dousen shelf button opens it again. A Maya started from a desktop shortcut has no Dousen panel. Restart Maya after you update DousenDesktop. If the panel header says Cannot connect to Dousen Desktop, open Desktop and the panel reconnects. See How the addons load. If your studio keeps DCC source files in a separate Perforce repository, possibly on another server, the same buttons act on that repository's server. See Source repositories for the admin binding and the artist workspace. ## Related - Maya addon reference - Perforce in the Dousen docs - One changelist per Jira task - Perforce actions in the DCC addons Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce in Substance Painter and Designer: check out, lock, sync and submit from the Dousen dock — Dousen URL: https://dousen.io/guides/perforce-in-substance-painter-designer.html Summary: How the Dousen dock in Substance Painter and Designer shows Perforce lock status, checks out, syncs and reverts files, and keeps textures in the Jira task changelist. By Luca Vitiello · Updated 6 October 2026 Dousen docks a panel in Substance Painter and Substance Designer. Its Perforce tab shows whether the open file is locked, opened by others or behind the depot, and lets you check out, sync and revert it under your own Perforce user. Published textures go to the Jira task's changelist. - Substance Painter and Substance Designer each show a docked Qt panel with a Publish and a Perforce tab. - The Perforce tab has Check Out, Sync & Reload, Revert and Refresh. - Painter's save-triggered publish runs the Perforce pre-flight; Designer has no auto-publish. - Textures export as TGA by default, or the format set in `export_presets`. - Textures need a target Unreal mesh before they publish. What changes for artists Launch the DCC from DousenDesktop. A DCC started from a desktop shortcut has no Dousen panel. DousenDesktop runs on Windows 10 and 11, and tasks come from Jira Cloud. ## What Perforce status do the Substance panels show? Painter shows a docked panel with the tabs Publish, Perforce, Export and Tools. Designer shows a docked panel with Publish, Perforce, Export, Materials and Tools. The Perforce tab shows live status for the open project or package, read with `p4 fstat` and refreshed about every 30 seconds. The panel header shows the current task and Stream: or Classic depot. | Status | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock, from an exclusive checkout or `p4 lock`. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open or locked, and your copy is current. | | P4 error: or Not in Perforce | Perforce can't answer, because the server is unreachable or the file isn't in the depot. | ## How do I check out, sync and revert a Substance file? - Open a project or package saved under your Perforce workspace root, then select the Perforce tab. - Click Check Out to edit an existing file. It opens in the selected Jira task's changelist, or in `default` if no task is active. - If the file is behind the depot, click Sync & Reload and confirm. The reload discards unsaved changes. - Click Revert and confirm to discard your changes to an open file. - Click Refresh to read the state again. The docs describe no new-asset setup for either application. Add a new source file in P4V after you save it under a mapped path, or let the publish add the files it creates, which happens after the export. ## How do exported textures land in the task's changelist? DousenDesktop sends the selected task's changelist to both applications. In Painter, Publish exports each checked texture set to the `Textures` folder under the source root and publishes one `texture.export` event per set. Designer's Publish bakes the graphs in each package once and publishes one event per checked graph. Dousen opens the scene and your previous outputs for edit in the task's changelist and adds new files after the export. Painter's Publish textures on save checkbox on the Tools tab gives the same handling on save. Designer has no auto-publish. A publish never submits. Follow One changelist per Jira task for that. The Perforce pre-flight covers Painter and Designer publishes and Painter's save-triggered publish. It doesn't cover Painter's own export dialog or Designer's export-only buttons on the Export tab, and Publish history doesn't list those exports. Check outputs from those paths out yourself if your workspace is read-only. After a restart, the first publish doesn't know the previous outputs either. ## What stops a publish in Painter or Designer? If another user has locked a file the export would write, the publish stops and names the lock in Publish history. Painter and Designer publishes also run the naming check first. Both also refuse a texture format that isn't in `texture.allowed_formats`, and validation reports an error named Target Unreal mesh when a Painter texture set has no target mesh. ## How do the Substance addons load? DousenDesktop ships both addons and loads them when you launch Painter or Designer from the apps bar, using the executable path in Settings → DCC Apps. The panel appears as a dock. An application started from a desktop shortcut has no Dousen panel, and a running session needs a restart after you update Desktop. Details are in How the addons load, Substance Painter and Substance Designer. If your studio keeps DCC source files in a separate Perforce repository, possibly on another server, the same buttons act on that repository's server. See Source repositories for the admin binding and the artist workspace. ## Related - Substance Painter and Substance Designer reference - Perforce in the Dousen docs - One changelist per Jira task - Perforce actions in the DCC addons Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Unreal Engine asset naming conventions: prefix reference — Dousen URL: https://dousen.io/guides/unreal-asset-naming-conventions.html Summary: A prefix and suffix reference for Unreal Engine 5 asset names: the Dousen style, built from Epic's recommended prefixes and the Allar structure, and how to enforce it. By Luca Vitiello · Updated 6 October 2026 Most Unreal Engine 5 projects name assets as Prefix_BaseName_Variant_Suffix, such as SM_Crate_01 or T_Brick_N. The Dousen style combines Epic's recommended prefixes with the Allar structure. Dousen enforces it from one YAML document per project, in every DCC before export and again when the DousenUE plugin imports. - The common pattern is `Prefix_BaseAssetName_Variant_Suffix`, for example `SM_Crate_01`. - The Dousen style uses Epic's prefixes, so `SM_` for a Static Mesh. The Allar style guide uses `S_`; Dousen ships that as a separate preset. - Texture suffixes name the channel, for example `_D` for base color and `_N` for normal. - Dousen stores the prefixes in one version 3 YAML document per project and checks them in every DCC before export. Epic's recommendation is `[AssetTypePrefix]_[AssetName]_[Descriptor]_[OptionalVariantLetterOrNumber]`. Epic also says the convention is only a recommendation and that your project's requirements take precedence. The tables below are the Dousen style: Epic's prefixes with Allar's structure. That means the PascalCase `Prefix_BaseAssetName_Variant_Suffix` pattern and texture suffixes of the community UE5 style guide (https://github.com/Allar/ue5-style-guide) by Allar (MIT). The Dousen (default) preset in the portal ships the DCC-created types (`SM_`, `SK_`, `A_`, `SKEL_`, `Rig_`, `T_` with channel suffixes, `MI_`, `HDA_`, `VAT_`). Engine-only types such as `BP_` and `WBP_` are listed here for reference and are not managed by Dousen conventions. Where Allar's own prefixes differ, the text says so. ## What are the prefixes for each asset type? ### Meshes and physics | Asset type | Prefix | Example | |---|---|---| | Static Mesh | `SM_` | `SM_Crate_01` | | Skeletal Mesh | `SK_` | `SK_Guard` | | Skeleton | `SKEL_` | `SKEL_Humanoid` | | Physics Asset | `PHYS_` | `PHYS_Guard` | | Morph Target | `MT_` | `MT_Smile` | ### Materials and textures | Asset type | Prefix | Example | |---|---|---| | Material | `M_` | `M_Concrete` | | Material Instance | `MI_` | `MI_Concrete_Wet` | | Material Function | `MF_` | `MF_Triplanar` | | Material Parameter Collection | `MPC_` | `MPC_Weather` | | Post Process Material | `PP_` | `PP_Outline` | | Physical Material | `PM_` | `PM_Gravel` | | Texture | `T_` | `T_Concrete_D` | | Texture Cube | `TC_` | `TC_Sky` | | Render Target | `RT_` | `RT_Minimap` | ### Animation | Asset type | Prefix | Example | |---|---|---| | Animation Sequence | `A_` | `A_Guard_Walk` | | Animation Blueprint | `ABP_` | `ABP_Guard` | | Animation Montage | `AM_` | `AM_Guard_Attack` | | Blend Space | `BS_` | `BS_Locomotion` | | Aim Offset | `AO_` | `AO_Rifle` | | Level Sequence | `LS_` | `LS_Intro` | ### Blueprints, data, AI, UI and effects | Asset type | Prefix | Example | |---|---|---| | Blueprint | `BP_` | `BP_Door` | | Widget Blueprint | `WBP_` | `WBP_MainMenu` | | Blueprint Interface | `BPI_` | `BPI_Interactable` | | Blueprint Function Library | `BPFL_` | `BPFL_Math` | | Data Table | `DT_` | `DT_Weapons` | | Behavior Tree | `BT_` | `BT_Patrol` | | Blackboard | `BB_` | `BB_Patrol` | | AI Controller | `AIC_` | `AIC_Guard` | | Font | `Font_` | `Font_Title` | | Particle System (Cascade) | `PS_` | `PS_Sparks` | | Niagara System | `NS_` | `NS_Sparks` | Some assets only take a suffix. Allar's guide uses `_P` for a persistent level, `_Audio`, `_Lighting`, `_Geo` and `_Gameplay` for sublevels, `_Cue` after `A_` for a Sound Cue, and `_SC` for a Sound Concurrency. Epic's page also lists Niagara asset prefixes under `FXS_` (system), `FXE_` (emitter) and `FXF_` (function). Pick one scheme for effects and keep it. Both source pages carry longer lists than this one, covering AI, media, Paper 2D and more. ## What suffixes do textures and meshes use? | Texture content | Suffix | Example | |---|---|---| | Diffuse, albedo, base color | `_D` | `T_Brick_D` | | Normal | `_N` | `T_Brick_N` | | Roughness | `_R` | `T_Brick_R` | | Alpha, opacity | `_A` | `T_Leaf_A` | | Ambient occlusion | `_O` | `T_Brick_O` | | Bump | `_B` | `T_Brick_B` | | Specular | `_S` | `T_Brick_S` | | Emissive | `_E` | `T_Lamp_E` | | Metallic or mask | `_M` | `T_Rail_M` | | Packed channels | letters stacked, such as `_ORM` | `T_Brick_ORM` | Allar's guide stacks the suffix letters of packed textures, for example `_ERO` for emissive, roughness and ambient occlusion. `_ORM` (occlusion, roughness, metallic) is the same rule applied to the common glTF-style pack. Whatever order you choose, write it down once. For variants, use a descriptive word (`_Snow`) or a two-digit number starting at `01`. Allar's guide notes you should never need a three-digit variant number. Neither source fixes a naming scheme for LODs, so choose one, such as `_LOD0`, `_LOD1`, and apply it everywhere. ## How should the folders be organized? Allar's guide puts all project assets under `/Content/ProjectName/`, uses PascalCase for every folder, allows no spaces or symbols, avoids empty folders, and avoids redundant type folders such as `Meshes` or `Textures`. Group by what the asset is, for example `Characters/Common/Animations/Locomotion`, so one feature's meshes, materials and textures sit together. ## What breaks when names drift? - Content Browser search and filters stop finding assets. Searching `SM_` misses a mesh named `Crate_Mesh`. - Renaming or moving an asset in the editor leaves a redirector behind. Redirectors pile up and have to be fixed up before a clean cook. - Cook and chunking rules, and scripts that match on path or prefix, miss assets that don't follow the pattern. - Reviewers can't tell a material from an instance or a normal map from a mask without opening the asset. ## How do you enforce the convention? A style guide only works if something checks it. In Dousen, a project admin writes the convention as one YAML document per project, in the web portal's Conventions tab. The current schema is version 3. Each asset type gets a `prefix`, optional `naming.pattern` and `naming.max_length` guard rails, and a tree of categories that can nest to any depth and add folders and name tokens. Studios that need computed rules can write the document as a Lua script instead. The Preset list offers Dousen (default), the DCC-created types of the style on this page, and UE5 Allar Style Guide with Allar's own prefixes. ``` version: 3 asset_types: static_mesh: prefix: SM suffix: "" naming: pattern: "^SM_[A-Z][A-Za-z0-9]*(_[A-Za-z0-9]+)*$" # PascalCase, single underscores max_length: 64 categories: Props: folder: true subcategories: Weapons: folder: true prefix: Wep ``` Dousen checks names in every supported DCC before export, with the `naming.convention` rule, and the DousenUE plugin builds the asset's name and Content Browser folder from the same document when it imports. A mesh that violates its pattern is blocked at the DCC before it reaches Perforce (in Houdini, run Dousen: Validate first; its export tools don't block). Existing Unreal assets aren't renamed when you change a rule. See Naming conventions for the full keyword reference and Unreal Engine for the import side. To test a name without installing anything, use the online naming checker. ## Sources - Epic Games, Recommended Asset Naming Conventions in Unreal Engine projects (https://dev.epicgames.com/documentation/en-us/unreal-engine/recommended-asset-naming-conventions-in-unreal-engine-projects) - Allar, UE5 Style Guide (https://github.com/Allar/ue5-style-guide) (MIT license) ## Related - Naming conventions and Unreal Engine in the documentation - Naming checker - What to validate in an FBX before Unreal imports it Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## What to validate in an FBX before Unreal imports it — Dousen URL: https://dousen.io/guides/validate-fbx-before-unreal-import.html Summary: A pre-import checklist for FBX files going into Unreal Engine, with the problem each check prevents and the Dousen validator rule that catches it in the DCC. By Luca Vitiello · Updated 6 October 2026 Before an FBX goes into Unreal Engine, check its names, triangle count, geometry, UVs, applied transforms, units, skeleton, animation frame rate and materials. Dousen runs these checks in the DCC on the instances you publish, so an error blocks the export and the problem never reaches Perforce or Unreal. - The checks run in the DCC on the instances you check, before anything is exported. - A rule set to `error` blocks the publish. A `warning` is advisory but you confirm it first. - A warning needs your confirmation before you publish. - Project admins turn rules on and off, and change severity and parameters, on the portal's Validators tab. ## What should you check before importing an FBX into Unreal? The table lists checks that Dousen's built-in validators cover, with the symptom you would otherwise see in Unreal. Defaults are the baseline, and a project's conventions can change them. Which rules run depends on the DCC, so see DCC coverage. | Check | Why it matters in Unreal | How Dousen checks it | |---|---|---| | Name follows the convention | Search, filters and cook rules depend on the prefix. The DousenUE plugin also checks the package name and required tags before it creates an asset. | `naming.convention`, error by default. Checks the prefix and the convention's pattern and length. | | No special characters in names | Spaces and symbols in object or file names can end up in the Unreal asset name and path, where they cause import and reference problems. | `naming.no_special_chars`, error. | | Triangle count within budget | A mesh over the triangle budget costs more memory and render time on every instance in the level. | `mesh.poly_count`, error, `max_tris = 50000` by default. | | No n-gons | Faces with five or more sides get triangulated on import in a way you don't control, which can shade differently. | `mesh.no_ngons`, warning, off by default. | | No zero-area faces | Degenerate faces give bad tangents and shading artifacts. | `mesh.no_zero_area`, error. | | No non-manifold geometry | Edges shared by more than two faces produce unreliable normals and collision. | `mesh.no_nonmanifold`, error. | | Watertight, consistent normals (Nanite meshes) | Nanite renders open edges as missing triangles, and flipped faces show up pink in the Nanite viewport. | `mesh.watertight`, `mesh.consistent_normals`, `mesh.no_loose_geometry`. | | Lightmap UVs on non-Nanite meshes | A baked-lighting mesh with no second UV channel gives lightmap errors in the build. | `nonnanite.lightmap_uvs`, warning. `uvs.no_overlap_lightmap` flags overlaps that bake as light bleed. | | UV coverage | Small UV islands leave most of the texture unused, so the mesh looks blurry at the same texture size. | `uvs.min_coverage`, warning, `min_coverage = 0.65`. | | Transforms applied | Unapplied scale or rotation imports with wrong size or orientation. | `scene.transforms_applied`, error. Blender and Maya offer an automatic fix. | | Scene units and frame rate (3ds Max) | A scene in the wrong units imports at the wrong scale. | `scene.units` (centimeters by default) and `scene.frame_rate` (`fps = 24` by default). These are 3ds Max rules. Other DCCs use `anim.fps_match` (`target_fps = 30`). | | No hidden objects | A hidden mesh is usually left over from authoring and shouldn't ship. | `scene.no_hidden_objects`, warning. | | No missing material slots | Empty slots import as blank or default materials. | `materials.no_missing_slots`, error. | | Single root bone, root at origin | Several roots or an offset root cause skeleton problems and animation offsets. | `rig.hierarchy`, `rig.root_at_origin`, both error. | | At most 4 skin influences per vertex, no unweighted vertices | Extra influences are dropped and unweighted vertices stay behind when the mesh moves. | `rig.max_influences` (`max_influences = 4`), `rig.unweighted_vertices`. | | No negative bone scale | Mirrored or flipped joints import with inverted scale, which distorts skinning and breaks retargeting. | `rig.no_negative_scale`, error. | | Frame rate matches the project | A clip at the wrong rate plays too fast or too slow. | `anim.fps_match`, error, `target_fps = 30`. | | Valid frame range, no keys on frame 0 | Unreal expects keys from frame 1 onwards. | `anim.frame_range`, `anim.no_keys_on_frame_zero`. | Which of the mesh rules apply depends on how the asset's materials are set up. Dousen runs either the Nanite rules or the non-Nanite rules for each asset, chosen from the project's material catalog. That gate is a preview feature. See Nanite rules and Materials. ## What happens when a check fails? Each rule has a severity. An `error` blocks the export, and the artist has to fix the problem first. A `warning` is advisory, but you confirm it before publishing: Blender shows Publish despite validation warnings, and the Qt Publish tab in Maya, 3ds Max and Substance asks "Publish anyway?". Expand a failing rule in the results to see the affected objects and its message. Use Select Invalid (Maya and 3ds Max) to select them in the scene, and Repair (Fix in Blender) when the rule offers an automatic fix. Houdini is the exception to blocking. There, validation is the manual Dousen: Validate shelf tool, and the export tools don't wait on it. If a rule seems wrong for your project, send your project admin the rule name, the message, the asset type and an example. ## Where are the rules configured? In the web portal, a project admin opens Projects, selects the project and opens Validators. The tree has Global, one node per asset type, and every taxonomy node. Each node can add a rule, turn it off, change its severity (`error` or `warning`) and edit its parameters, and a deeper node overrides a shallower one. A hero-prop node can set a lower `max_tris` than the global rule. The editor saves each change as you make it. DCCs cache conventions for up to five minutes, so wait or relaunch the DCC before you test a change. The full list of rules and how to write your own is in Asset validation. ## Can I add my own checks? Yes. Studios can load custom validators into the DCC addons through the `validators.extra_paths` setting in the project's pipeline settings, and load their own tools and startup scripts alongside the Dousen addon. See custom validators and Loading studio tools. ## Source - Epic Games, FBX Content Pipeline (https://dev.epicgames.com/documentation/unreal-engine/fbx-content-pipeline?lang=en-US), with pages for static mesh, skeletal mesh, animation and material import ## Related - Asset validation and DCC addons in the documentation - Unreal asset naming conventions - One Perforce changelist per Jira task Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. # Free tools ## DousenClips user guide — Dousen URL: https://dousen.io/tools/dousenclips-guide.html Summary: DousenClips for Maya: installation, first export, independent takes, subclips, poses, libraries and troubleshooting. By Luca Vitiello · Updated 6 October 2026 DousenClips is a free Maya tool from Dousen for organizing animation clips and exporting them to FBX. This guide covers installation, your first export, independent takes, subclips, poses, import, external libraries and troubleshooting. This guide covers installing DousenClips in Maya, organizing animation clips and exporting them to FBX. DousenClips is free and needs no Dousen license. For an overview of the tool, see the DousenClips page. - Maya 2025 or later with PySide6. - Free, with no Dousen license required. - DousenDesktop is optional; the tool works on its own. ## 1. Getting started: install once, open from the shelf DousenClips runs inside Autodesk Maya. It stores clip definitions with your scene and exports animation through a temporary, clean skeleton. DousenDesktop is optional; you can use the tool on its own. ### What you need - Maya 2025 or later with PySide6. The screenshots and export walkthrough here were captured in Maya 2027 on Windows. - The complete DousenClips distribution, including `install.py`, `scripts` and `icons`. This guide is documentation, not the installer. - A rig with an exportable joint hierarchy. For independent takes, the rig also needs an `anim_controls` selection set. - Extract the package to a permanent folder. For example, `C:/Tools/DousenClips`. Keep the folder's contents together. - Open Maya. Drag `install.py` from your file manager into the Maya viewport. - Open the Dousen shelf. Click the mint filmstrip Dousen Clips button, labeled "Clips" on the shelf. The installer registers the folder as a Maya module and adds or updates the shelf button. Running it again updates that button without creating duplicates. Keep the installed folder in place. ### If the shelf button is missing In Maya's Script Editor → Python tab, run: ``` from dousenclips.ui import show show() ``` If Python cannot find `dousenclips`, rerun the installer from the extracted folder and restart Maya. ### Manual installation Create `DousenClips.mod` in your Maya user `modules` directory. On a typical Windows setup this is `Documents/maya/modules`; a customized Maya user directory may differ. Use your actual installation path: ``` + DousenClips 1.0 C:/Tools/DousenClips PYTHONPATH +:= scripts ``` Restart Maya, then run the Python launch command above. Manual module setup alone does not create the shelf button. ### Update or remove For an update, close Maya, replace the installed package with the new complete version, then rerun its installer. To remove it, run `python install.py --uninstall` from the package folder. When run outside Maya, remove any remaining shelf button manually. Your animation scenes and exports remain separate from the installation. ## 2. Your first export: turn animation into named clips Start with a saved scene and one character. A clip set groups a rig's clips and export settings; each clip describes an animation range or owns an independent take. - Add your rig. Select a rig control or joint and click Add rig. Check that the Rig selector points to the expected skeleton. If an `export_skel` selection set exists, it takes priority during detection. - Choose your workflow. For ordinary timeline clips, highlight a frame range with Shift-drag on Maya's timeline, or set the playback range, then click + in the CLIPS tab. Name the clip, for example `Idle`. See the note below if the rig uses independent takes. - Review the range. Right-click → Edit range… and set Start and End together in one dialog, or use Set range from timeline. This works for internal clips, takes and external clips; external clips require Edit / Check Out first. End frames are inclusive: 1–24 contains 24 frames. - Choose an export profile. Select unreal or unity in the header. - Choose a destination. Click the … beside the export path. Set Export prefix to a useful character or scene name. - Tick the clips to export. Click Export, then check each clip's result. Use the folder button to inspect the written files. When + creates a new take: if the rig has an `anim_controls` set, or the set already contains takes, + creates and activates a new take from the default pose. It does not capture your existing animation. Use Capture take from current range on an existing timeline clip to capture authored animation, or Import clips from files… to bring in animation scenes. Save before changing workflows. ### What success looks like The clip cards show green OK results. The demo exported: ``` Robot_Idle.fbx Robot_Bounce.fbx Robot_Wave.fbx Robot_Wave.notifies.json ``` `Robot` is the export prefix. Wave includes a notify, so it also produces an event sidecar. The screenshot uses `$CLIPS_EXPORTS`, an environment variable configured for this demo. For your first export, browse to a normal folder. Selection and export checkboxes are different. The main Export button processes enabled clips in the current tab. To export only highlighted rows, right-click → Export selected. Those rows must still be enabled. A text filter is for finding clips; use checkboxes or Export selected to control output. ## 3. Find your way around: a short tour of the panel | Control | Use it for | |---|---| | Rig | Switch between clip sets for different characters in the same scene. | | Profile | Choose engine export policy. Unreal is the default; Unity uses a character@clip naming convention. Custom is a neutral base for pipeline configuration. | | ⋯ tools menu | Import animation, create clips from bookmarks, render previews, exchange JSON and manage external libraries. | | Filter | Find clips by name. | | CLIPS / POSES | Work with animation ranges or single-frame poses. | | Clip card | Read its name, frame range, frame count, loop flag and status. The colored square identifies its timeline color. | | Checkbox | Include or exclude a clip from export. | | + / trash | Create a clip or pose, or delete selected definitions. Save your work before removing clips or takes. | | Export prefix | Defaults to the saved scene's filename without its extension. Edit to override, or clear for no prefix. An unsaved scene has no automatic filename prefix. | ### Useful gestures - Double-click a clip to activate it or frame its timeline range. - Press `F2` on a clip to rename it. - Right-click for clip settings and export actions. - Use Maya's colored timeline bookmarks to see animation ranges. - Change a clip's color through its context menu. For a captured take, Activate swaps its animation onto the rig. For a timeline-only clip, it frames the relevant timeline range. ## 4. Independent takes: when clips need their own animation There are two ways a clip can relate to animation. - Timeline clips are named windows into one continuous animation timeline. Overlapping clips read the same underlying animation. - Independent takes each own captured animation. Activate one to edit it on the rig, then switch to another clip's animation. ### Capture existing animation - Ensure the rig has an `anim_controls` selection set containing the controls whose animation the take must own. This is different from the export joint set. - Start from an existing timeline clip with the correct range and animation currently on the rig. - Right-click → Capture take from current range. - Double-click the captured clip to activate it. New captures normally use a local timeline beginning at frame 1. - Animate normally. Switching away from an embedded active take captures its current edits before activating the next one. Save the Maya scene to persist your work. A clip marked ACTIVE owns the animation currently connected to that rig. Only one take per rig is active at a time. Imported takes can begin at frame 0; follow the range displayed on the card. ### Start a new animation On a rig configured for takes, click +, name the new take, and animate from its default pose. The active take's bounds follow Maya's Animation Start/End fields. Adjusting those bounds does not move or delete keys; the playback preview range stays within them. ### Layers and related clips Takes can retain editable Maya animation layers. The clip menu provides layer actions. A derived clip shares a parent's captured base and adds its own layers or overrides; a variant is useful for alternative layer-state combinations. A mirror action creates an opposite-side take when the rig's joint naming or mirror mapping supports it. Embedded versus external: switching embedded takes captures changes in scene memory. External-library clips need Save Clip to write their authoritative file. Neither workflow makes saving your Maya working scene unnecessary. ## 5. Subclips and poses: split a performance into Start, Loop and End - Activate the parent animation. - Shift-drag a range on Maya's timeline. - Right-click that range → Create Sub-Clip, then give it a name. - Repeat for other sections. Right-click the looping section and enable Loop. - Double-click a child to preview its range. Resize its timeline bookmark or use Edit range… to adjust it. A subclip shares its parent's animation, layers and morph controls, while keeping its own range and loop flag. It can be exported separately. The example divides a 33-frame take into 1–8, 9–24 and 25–33. A selected range of 10–19 is exactly ten frames. ### Capture a pose Move to the desired frame, switch to POSES, then click its capture button. Name the pose and review its frame. When the rig is configured for takes, pose capture also stores the current pose as an owned take. Double-click to activate or go to it, and export from the POSES tab. ## 6. Polish your export: set motion, loops and events ### Root motion Right-click a clip → Root motion. Choose the mode that matches your engine setup: | Mode | Result | |---|---| | `authored` | Preserve the root motion authored on the rig. | | `in_place` | Zero the configured root channels on the export skeleton. | | `hip_extract` | Transfer world-space hip movement to the export root, useful for pelvis-driven rigs. | | Origin at start | Offset exported motion relative to its starting position. | | Inject root joint | Add an export root for a rig that needs one, such as a pelvis-rooted hierarchy. | These operations affect the temporary export skeleton. Review a test FBX in your target engine before committing a whole animation set. ### Loop and Loop snap Loop marks the animation as looping and checks the first/last-frame seam after baking. Loop snap re-keys the final frame to the first on the export skeleton. It can close a seam, but it does not replace checking the quality and rhythm of the cycle. ### Animation-layer state Set the scene's layer mute, solo and weight values, then use Capture animation-layer state on the clip. This allows, for example, normal and injured versions of the same motion. Export applies the stored state and restores the original scene layer state afterwards. ### Notifies: footsteps, hits and effects From the timeline: activate the clip, move the playhead to the event frame, then right-click Maya's timeline → Add Notify at Current Frame. Enter the event name. The event appears as a one-frame timeline bookmark. From the clip: right-click its card → Edit notifies… to add or edit events, change their frames and names, or supply an optional JSON object in Params. Keep event frames inside the clip's range. For an independent take, use its local frame numbers. Export writes a `.notifies.json` sidecar and attempts to encode event spike curves in the FBX. Keep the JSON beside the FBX for your pipeline. This does not automatically create native Unreal AnimNotifies; that requires an importer or manual setup in the engine. ## 7. Import and backup: bring scenes in, keep useful copies ### Import animation files - Add the destination rig, with its `anim_controls` set. - Open the ⋯ menu → Import clips from files…. - Select Maya `.ma` or `.mb` scenes using the same rig and frame rate. - Review the imported clips and play each one. The source scene's saved Animation Start/End determines its range, retimed to start at 0. Import creates new clips. Matching files such as `Jump_Start.ma`, `Jump_Loop.ma` and `Jump_End.ma` can become one parent animation with consecutive subclips; the Loop section is flagged as looping. The tools menu can also import definitions from Maya Game Exporter, Time Editor or timeline bookmarks. These are separate import paths from reading animation scene files. ### Save and back up - Save the Maya scene to preserve embedded clips and animation. - Use Export sidecar JSON… to create a portable clip metadata snapshot; captured takes can round-trip through this format too. - Keep the rig, its references and the Maya scene. A JSON sidecar is not a complete character or project backup. - Use Import sidecar JSON… for transfer or recovery against the appropriate rig. ### Preview GIFs Choose Render clip previews (playblast) in the tools menu. Once rendering finishes, hover over a clip to see its animated preview. For embedded clips, the GIFs are saved under `.dousenclips_previews`. ## 8. External clip libraries: one animation, one complete Maya scene An External Clip Library stores each animation in a standalone Maya scene, including its rig, geometry, references, constraints and animation layers. Open the scene to animate or export it. There is no need to import disconnected curves into a separate working rig. - Open Tools → External Clip Library. Choose Create Scene Library, or Convert Animations to Scenes to copy existing embedded or legacy library animations into an empty folder. - Choose Standalone for local use or Perforce for exclusive team checkout. - Choose Browse Scene Library. Each entry represents one full animation scene. Subclips remain sections inside their parent scene. - Open Scene or double-click to open a local preview copy. Maya asks how to handle unsaved changes when leaving the current scene. - Choose Edit / Check Out to open a working copy with ownership, or Edit / Check Out Current Scene after opening a preview. - Animate and use the normal DousenClips export controls to export this scene's animation or its subclips. - Choose Save Library Scene to publish the complete scene. Submit or shelve through your usual Perforce client. Maya Save keeps your local working copy. Use Save Library Scene to update the shared animation scene. A library save verifies the full scene, requires ownership and refuses changed source revisions. It does not submit or release a Perforce checkout. Keep regular local scene saves. Use Add Current Animation in the browser to add an existing scene with one DousenClips animation. Scenes containing several animations use Convert Animations to Scenes instead. Conversion copies the full scene for each animation, makes variants and derived takes independent, and preserves the original scene and legacy library files. The browser shows source-control ownership next to each entry. Standalone libraries are single-writer local libraries. Perforce sources require exclusive-open `+l` file types. Status checks do not automatically sync or check out files; sync using your normal Perforce client, then reopen the entry. Library scenes are native Maya ASCII files and can open directly in Maya. Referenced rigs, textures and plug-ins still need their normal project dependencies. The Legacy Curve Library menu remains available for older libraries. ## 9. Troubleshooting: when something does not look right | Symptom | Try this | |---|---| | No shelf button / import error | Confirm the package was extracted completely, rerun `install.py` from its permanent folder, then restart Maya. Try the Python launch command in section 1. | | Add rig finds the wrong skeleton | Select the intended root joint and check the contents of any `export_skel` selection set. Confirm the Rig dropdown before creating clips. | | + creates a blank/default pose | The rig is configured for independent takes. Capture an existing timeline clip or import animation files to preserve an authored performance. | | Nothing to export | Check the current CLIPS/POSES tab and clip checkboxes. For Export selected, select the intended rows and ensure they are enabled. | | Too many clips exported | The main Export button uses enabled clips, not just highlighted rows. Use Export selected for a subset. | | Export blocked or failed | Read the validation message or clip result. Check root hierarchy, ranges, filename collisions, missing layers and output-folder access. For FBX plug-in errors, check Maya's `fbxmaya` plug-in. | | Take capture misses controls | Check that `anim_controls` contains the intended rig controls and that its membership matches the character. Re-capture only when the correct animation is on the rig. | | File import fails to match a rig | Use the same rig and frame rate. Missing channels or ambiguous control names must be fixed; the importer rejects partial matches. | | Loop seam or root drift | Review Loop/Loop snap and root-motion settings. Test the FBX in the target engine before batch export. | | External clip cannot save | Choose Edit / Check Out, inspect the owner/revision tooltip and resolve source-control or disk changes. Reopening Maya requires reacquiring edit ownership for external saves. | ### Publishing with Dousen When the Dousen Maya addon is installed, checked takes and subclips appear automatically in its Publish tab. Both panels share their checkboxes. DousenClips Export uses Dousen validation, project output paths, checkout and per-instance publish bundles, including notifies. Errors block export; warnings ask for review. A rejected publish does not fall back to standalone export. Update the Dousen addon if prompted. In a scene library, Maya Save keeps the local working scene, Save Library Scene writes the shared animation source, and Export publishes the selected animation assets through Dousen. Without Dousen installed, standalone FBX export remains available. ### For pipeline users: headless export Run with Maya's `mayapy` and make the installed package's `scripts` directory available on `PYTHONPATH`. Replace the scene, set and clip names below with your own: ``` mayapy -m dousenclips list scene.ma mayapy -m dousenclips export scene.ma --set hero_clips --clips walk,run --profile unreal --out C:/Exports --report report.json ``` Exit codes: `0` success, `1` clip failures, `2` validation blocked, `3` usage or scene error. Screenshots in this guide were captured from the DousenClips panel in Maya 2027 on Windows, using a purpose-built robot demo. The walkthrough exported three FBX animations and a notify sidecar. It did not exercise every engine, installer platform or Perforce team workflow. The Dousen integration screenshot uses an isolated Maya test rig. The demo character is illustrative; use your own production rig and project paths. ## Related - DousenClips: free Maya animation clip exporter - Dousen in Maya - Validate an FBX before Unreal import Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## DousenClips: free Maya animation clip exporter — Dousen URL: https://dousen.io/tools/dousenclips.html Summary: DousenClips is a free Maya tool to define, manage and batch-export animation clips and poses to engine-ready FBX for Unreal and Unity, with no license required. By Luca Vitiello · Updated 6 October 2026 DousenClips is a free Maya tool from Dousen for defining, managing and batch-exporting animation clips and poses as engine-ready FBX. Clips live in your scene as lightweight nodes, and each export bakes onto a temporary clean skeleton, so your rig is never touched. It needs no license. - Free, with no license required. - Runs in Autodesk Maya 2025 or later (PySide6). - Exports FBX with Unreal and Unity profiles. - Clips are lightweight network nodes, so no plug-in `requires` line is written into your scenes. - Runs headless with `mayapy -m dousenclips`. - Works on its own, with optional Dousen integration. New to the tool? Start with the DousenClips user guide, a full walkthrough with screenshots. Jump to the download. ## What does DousenClips do? You work in clip sets, one per rig. A clip set holds clips (named frame ranges) and poses (single frames), and every clip also appears as a colored, named timeline bookmark. When you export, DousenClips duplicates the bind skeleton, strips it to joints, constrains it to the rig, bakes the animation, writes the FBX and deletes the duplicate. The rig, your keys and the timeline stay as they were. The Export prefix field defaults to the scene name, so clip `Walk` in `Hero.ma` exports as `Hero_Walk.fbx`. ## What makes it different? - Clean export skeletons: no rig leakage, no namespaces in the FBX, and no empty files from a forgotten Bake Animation option. - Per-clip animation-layer states: one timeline can emit `Walk`, `Walk_Injured` and `Walk_Aim`, and your layer stack is restored afterwards. - Per-clip root motion: `authored`, `in_place` or `hip_extract`, with origin-at-start grounding and root-joint injection. - Mirror-bake: author `Strafe_L` and ship `Strafe_R`, flipped on the throwaway skeleton. - Loop seam check after baking, with an optional snap that closes the seam on the export skeleton only. - Engine profiles (`unreal` and `unity`) and output paths with `{clip}`, `{set}`, `{character}`, `{scene}` and `{profile}` tokens. - Gameplay curves and anim notifies. Notifies are mirrored as timeline bookmarks, and every export writes a `.notifies.json` sidecar. - Independent takes, an opt-in mode where each clip owns its captured animation instead of sharing the timeline. ## What do I need? - Autodesk Maya 2025 or later with PySide6. The screenshots in the guide were captured in Maya 2027 on Windows. - A rig with an exportable joint hierarchy. An `export_skel` selection set is honoured when present. - For independent takes, an `anim_controls` selection set naming the rig's animation controls. - No license, no account and no server. Dousen itself is optional. ## Where is the documentation? The DousenClips user guide covers everything, with screenshots from a live Maya session: - Install once, open from the shelf, including the manual `.mod` file and how to update or remove it. - The first successful export: add a rig, create clips, export, read the results. - Animation ownership: timeline clips against independent takes, layers and derived clips. - Start, Loop and End subclips and poses. - Export settings: root motion, loop snap, layer states and notifies. - Importing scenes, sidecars and preview GIFs, and the scene library team workflow. - Troubleshooting, publishing through Dousen, and the headless `mayapy -m dousenclips` command line. ## How does it work with Dousen? DousenClips works without Dousen. If the Dousen Maya addon is installed, checked DousenClips takes and subclips also appear in Dousen's Publish tab, and both panels share the checkboxes. DousenClips Export then runs Dousen's validation, checkout and publish workflow. Validation errors stop the export and warnings ask for review. See Dousen in Maya for the addon. ## Where do I download DousenClips? DousenClips is in beta. Builds are published at dl.dousen.io/dousenclips/ (https://dl.dousen.io/dousenclips/); if the link below has nothing behind it yet, email hello@dousen.io for the current build. Download DousenClips (latest beta) (https://dl.dousen.io/dousenclips/DousenClips-latest-beta.zip) Install steps One zip for Maya 2025 and later, any platform. Unzip, then drag `install.py` into the Maya viewport. The zip contains the Python sources, the user guide and a `LICENSE.txt`: free to use in personal and commercial projects, no redistribution or modification. ## Related - DousenClips user guide - Validate an FBX before Unreal import - Dousen in Maya Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Free tools for Unreal and DCC pipelines — Dousen URL: https://dousen.io/tools/index.html Summary: Free tools from Dousen: an Unreal asset naming checker, a Perforce .p4ignore and typemap generator, and DousenClips, a Maya animation clip exporter. By Luca Vitiello · Updated 6 October 2026 Dousen publishes three free tools for game asset pipelines: a naming convention checker for Unreal Engine assets, a Perforce ignore and typemap generator for Unreal and DCC projects, and DousenClips, a Maya animation clip exporter. The browser tools run client-side and need no account; DousenClips installs into Maya with no license. All produce files you can use with or without Dousen. [Image: DousenClips running in Maya 2027 with a simple robot and three exported animation clips] DousenClips for Maya Free Maya tool: define animation clips and poses in the scene and batch-export engine-ready FBX with root motion, loop checks and notifies. No license needed. Read the user guide. Unreal asset naming convention checkerTest asset names against the Dousen style, the Allar style guide or a prefix-only rule set, then export a Dousen conventions YAML file. Perforce .p4ignore and typemap generatorGenerate an ignore file and p4 typemap entries for Unreal Engine 5, Blender, Maya, 3ds Max, Houdini and Substance. Both tools run in your browser and send nothing to a server. ## Related - Naming conventions - Perforce in Dousen - Guides Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Unreal asset naming convention checker — Dousen URL: https://dousen.io/tools/naming-checker.html Summary: Free browser tool. Check Unreal Engine asset names against the Dousen style (Epic prefixes, PascalCase), the Allar style guide or a prefix-only rule set, then export the rules as a Dousen conventions YAML file. By Luca Vitiello · Updated 6 October 2026 Paste Unreal asset names into this free checker to test them against the Dousen style, the UE5 style guide by Allar, or a prefix-only rule set. Each name gets a pass or fail with a reason. You can export the rules as a Dousen version 3 conventions file, which Dousen then enforces in Blender, Maya, 3ds Max, Houdini, Substance and Unreal. - Runs in your browser. Nothing you paste is uploaded. - Three rule sets: Dousen style (default): based on the preset the portal ships, plus common engine-only prefixes that are checked here but left out of the YAML export, the UE5 style guide by Allar, and a prefix-only set. - Checks the prefix, length, allowed characters, underscores and, in the Dousen and Allar styles, casing. - Exports a version 3 Dousen conventions YAML file from the prefix table and options. Convention Dousen style (default) UE5 style guide (Allar) Minimal (prefix only) Max length Allowed characters (regex) Require the `Prefix_` form Asset names, one per line Check names | Name | Detected type | Result | Reason | |---|---|---|---| ### Prefix table Edit any cell, remove a row or add your own. The Dousen key column is the asset type id used in the export. Rows without one are checked here but left out of the YAML. | Asset type | Dousen key | Prefix | Suffix | Remove | |---|---|---|---|---| Add row Export as Dousen conventions YAML ``` ``` Copy Download .yaml ## How does the checker decide? The checker reads everything before the first underscore as the prefix and looks it up in the prefix table. A match gives the asset type. Where several rows share a prefix, such as the texture rows that all start with `T_`, a row with a suffix wins when the name ends with it. Then it applies the options above. | Failure | What triggers it | |---|---| | Unknown prefix | The prefix isn’t in the table, or the name has no `Prefix_` form while that option is on. | | Prefix case | The prefix matches a row only when case is ignored, such as `bp_` for `BP_`. | | Too long | The name is longer than the max length. | | Bad characters | The name doesn’t match the allowed-characters expression. | | Missing suffix | The prefix only matches rows that need a suffix, such as the `T_` texture rows, and the name ends with none of them. The reason lists the suffixes, for example `missing suffix (_D, _N)`. | | Nothing after the prefix | The name is a known prefix and an underscore with no base name, such as `SM_`. | | Double or trailing underscore | Dousen and Allar styles. The name contains `__` or ends with `_`. | | Lowercase base name | Dousen and Allar styles. The part after the prefix doesn’t start with an uppercase letter. | The Dousen style is based on the Dousen (default) preset that ships in the Dousen portal, with common engine-only prefixes added that this page checks but doesn't export: the prefixes from the Unreal Engine documentation (https://dev.epicgames.com/documentation/en-us/unreal-engine/recommended-asset-naming-conventions-in-unreal-engine-projects) (`SM_`, `SK_`, `T_`, `MI_`) with the structure of the UE5 style guide by Allar (https://github.com/Allar/ue5-style-guide): `Prefix_BaseAssetName_Variant_Suffix`, PascalCase, single underscores, and only `A-Z`, `a-z`, `0-9` and `_`. The Allar option mirrors Dousen’s UE5 Allar Style Guide preset, which keeps Allar’s own prefixes, such as `S_` for a Static Mesh. Change any prefix in the table to match your project. ## What does the YAML export contain? The export writes `version: 3`, the two global naming validators, and one entry under `asset_types` for each row that has a Dousen key. Each entry has the `prefix`, an optional `suffix`, and a `naming` block with a `pattern` and your `max_length`. In Dousen style the pattern requires `Prefix_`, a PascalCase base name and single underscores. In Allar and Minimal styles it allows letters, digits and underscores. Dimensions, categories and validator parameters aren’t part of it. Add those in the portal, as described in Naming conventions. To use the file, open Projects in the portal, select your project, open the Conventions tab, paste the YAML into the editor or use Upload File, then click Save. Clients cache conventions for 5 minutes. ## How does Dousen enforce the same rules? DousenCore compiles the document and the clients read the compiled result. The DCC addons for Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer report the `naming.convention` and `naming.no_special_chars` rules. A rule at error severity blocks the export and one at warning is advisory. In Substance Painter, Substance Designer and Houdini the rule checks the prefix only. The addons also suggest the name from the asset type and tags, so artists don’t type prefixes by hand. In Houdini, validation is the manual Dousen: Validate shelf tool, and the export tools don’t block on it. See the naming rules and DCC addons. On the Unreal side, the DousenUE plugin builds the asset name and Content Browser folder from the same conventions and checks the package name before it creates the asset. See Naming and destination. ## Related - Unreal asset naming conventions - Naming conventions reference - Asset validation - Perforce .p4ignore and typemap generator Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Perforce .p4ignore and typemap generator for Unreal and DCC projects — Dousen URL: https://dousen.io/tools/p4ignore-generator.html Summary: Free browser tool. Generate a Perforce .p4ignore and p4 typemap entries for Unreal Engine 5 projects and Blender, Maya, 3ds Max, Houdini and Substance files. By Luca Vitiello · Updated 6 October 2026 Pick the tools your project uses and this free generator writes a Perforce `.p4ignore` file and `p4 typemap` entries for Unreal Engine 5 and common DCC files. The typemap gives binary scenes and assets exclusive locks. Dousen then shows those locks in the Blender, Maya, 3ds Max, Substance Painter and Substance Designer panels and, in Houdini, through the Dousen: File Status (P4) shelf tool (on demand). - Runs in your browser. Nothing is uploaded. - Output A is a `.p4ignore` file for `p4 set P4IGNORE=.p4ignore`. - Output B is a typemap that gives `.uasset`, `.umap` and DCC scene files `binary+l` or `text+l`, so a checkout locks them exclusively. - Covers Unreal Engine 5, Blender, Maya, 3ds Max, Houdini, Substance Painter and Designer, Visual Studio and Rider. ### What is in your project? Unreal Engine 5 project Blender Maya 3ds Max Houdini Substance Painter Substance Designer Visual Studio / Rider macOS / Windows OS files Include comments Ignore `Binaries/` Typemap depot path ### .p4ignore ``` ``` Copy Download .p4ignore ### Typemap entries ``` ``` Copy Download typemap.txt ## How do I apply the files? - Save the ignore file as `.p4ignore` in the root of your workspace and run `p4 set P4IGNORE=.p4ignore`, without spaces around the `=`. Perforce then skips matching files when you add files or reconcile the workspace. - Ask a Perforce admin to run `p4 typemap`. The command opens the typemap form, and changing it needs admin access. Paste the generated lines under the existing `TypeMap:` field and save. Later entries override earlier ones. - Do this before the first `p4 add` of your content. The typemap only applies to files you add afterwards. To change a file that is already in the depot, run `p4 reopen -t binary+l ` and submit. The typemap pattern has the form `//depot/....uasset`. The first three dots match every folder below the path, and the fourth dot starts the extension. Change the depot path above to scope the rules to one project. ## Why does the typemap matter for binary assets? Perforce can’t merge a `.uasset`, a `.blend` or a `.max` file. The `+l` modifier makes a checkout take an exclusive lock, so a second artist can’t edit the same file and then lose work at submit. Without it, two people can open the same file, and the second to submit has to throw one version away. The `binary` base type stores each revision as a whole file, and `text+l` keeps text formats such as Maya `.ma` as text while still locking them. If you uncheck Ignore Binaries/, build output such as `.dll` and `.pdb` gets `binary+w` so it stays writable, which Epic’s guide gives as the reason to set a typemap. The typemap also gives `.fbx`, `.psd`, `.png`, `.tga` and `.exr` `binary+l` whatever you select. Delete those lines if you don’t want exclusive locks on textures and exports. The ignore file does the opposite job. It keeps generated folders such as `Intermediate/` and `DerivedDataCache/`, editor caches and DCC backup copies out of your changelists. The Substance Painter option adds no ignore entries, because no documented backup folder name was verified for it. ## How does Dousen show those locks? The Dousen panel in Blender, Maya, 3ds Max, Substance Painter and Substance Designer reads live Perforce status with `p4 fstat` and refreshes about every 30 seconds. In Houdini, the Dousen: File Status (P4) shelf tool shows it on demand. A file locked by someone else shows Locked by (CL n), and a publish stops before it exports if another user has locked a file the export would write. Checkout, revert, sync and add run under your own Perforce user, and they use the changelist of your active Jira task. With the typemap in place, an exclusive checkout from the panel is what produces the lock. Details are in File locks inside your DCC. For one DCC at a time, see Perforce in Blender and its sibling guides. ## Which sources were used? Each entry comes from one of these pages. Check them against your studio’s own rules before you submit the typemap. - Using Perforce as Source Control for Unreal Engine (https://dev.epicgames.com/documentation/en-us/unreal-engine/using-perforce-as-source-control-for-unreal-engine) (Epic Games): typemap, P4IGNORE syntax and the optional Binaries folder. - P4IGNORE (https://help.perforce.com/helix-core/server-apps/cmdref/current/Content/CmdRef/P4IGNORE.html) (Perforce): comment, `!`, `*`, trailing-slash and `p4 set` syntax. - p4 typemap (https://help.perforce.com/helix-core/server-apps/cmdref/current/Content/CmdRef/p4_typemap.html) (Perforce): field format, `....ext` patterns and override order. - How to use Unreal Engine 5 with Perforce (https://www.perforce.com/blog/p4/how-use-unreal-engine-5-perforce) and P4 typemap (https://www.perforce.com/blog/vcs/perforce-p4-typemap) (Perforce): `binary+l` for `.uasset` and `.umap`, and the modifiers. - Engine-agnostic P4 typemap (https://gist.github.com/jase-perf/3f6328fb66427802090f458775e481df) and Ignore file for Unreal Engine projects with common DCC ignores (https://gist.github.com/jase-perf/b15b57d72fa8095c732fdbc4ca948903) (jase-perf, community): the file types, `binary+w` build output, and Visual Studio, Rider and OS entries. - Best p4Ignore for Populating Perforce with UE4 Engine Source (https://forums.unrealengine.com/t/best-p4ignore-for-populating-perforce-with-ue4-engine-source/555073) (Epic forums) and ue4-perforce (https://github.com/mattmarcin/ue4-perforce/blob/master/.p4ignore) (community): the `Saved/`, `Intermediate/` and `DerivedDataCache/` list. - DCC backups: Blender Save & Load (https://docs.blender.org/manual/en/latest/editors/preferences/save_load.html) (`.blend1`, `.blend2`), Maya swatches (https://help.autodesk.com/cloudhelp/2026/ENU/Maya-ManagingScenes/files/GUID-67B3FB68-AAA4-415D-A37B-1EAC461613C0.htm), 3ds Max file preferences (https://help.autodesk.com/cloudhelp/2024/ENU/3DSMax-Customizing/files/GUID-1AA91F8A-CA4E-4432-9D54-1301305CB44C.htm) (`autoback`, `maxback.bak`), Houdini hipFile (https://www.sidefx.com/docs/houdini/hom/hou/hipFile.html) (`backup`) and Substance Designer preferences (https://helpx.adobe.com/substance-3d-designer/interface/preferences-window.html) (`.autosave`). ## Related - Perforce in Dousen - Perforce in Blender - One changelist per Jira task - Unreal asset naming convention checker Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. # Integrations ## Dousen + 3ds Max — Dousen URL: https://dousen.io/integrations/3ds-max.html Summary: How the Dousen 3ds Max addon works: the docked panel, node and selection-set instances, validation, publishing to Unreal, auto-publish on save and Perforce status. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for 3ds Max 2025 or later opens the same docked Qt panel as Maya. Each top-level node whose hierarchy contains a mesh becomes an instance, and named selection sets become instances you define yourself. You validate and publish checked instances to Unreal as FBX from the Publish tab. - Version: 3ds Max 2025 or later; the panel uses PySide6. - Load: launch 3ds Max from the apps bar in DousenDesktop; the panel opens at startup. - Menu: Dousen before the Help menu, with Dousen Panel, Publish and New Asset. - Exports: the instance’s nodes, plus skeleton root bones for a skinned mesh, as FBX. - Convention tags are written as `dousen_=` lines in each node’s user-defined properties. ## How does the addon load? DousenDesktop ships the addon and loads it when you launch 3ds Max from the apps bar. Check the executable path in Settings → DCC Apps. The panel has the same tabs as Maya: Publish, Perforce, New Asset, Materials and Tools. ## What becomes an instance? Each top-level node whose hierarchy contains a mesh. To create your own, make a named selection set; every named selection set becomes an instance. A selection set that holds only part of a node tree takes just those nodes out of the automatic instance, which keeps the rest. ## How do I validate and publish? - Open the Publish tab and click Reset to collect instances. - Check the instances to publish. Right-click to Set Type or Set Import Profile. - Click Validate. Select Invalid selects failing nodes. 3ds Max has no built-in fixes, so Repair appears only for rules that provide one. - Click Publish. Errors stop it. - Check Publish history in DousenDesktop. 3ds Max uses the same rule IDs as Blender and Maya for naming, mesh hygiene, Nanite and NonNanite, and covers scene, materials, rig and animation with its own host-specific rules. ## Can 3ds Max publish on save? Yes. Check Publish mesh.export on save on the Tools tab. Each save publishes the checked instances without running the validators, though it still checks instance names, so a naming rule set to error can stop it. The setting lives in the scene, so check it when you open another file. ## What does the panel header tell me? The header of the Qt panel shows the current Jira task and the Perforce stream, or `Classic depot` for a project without streams. After you switch tasks in DousenDesktop, check the header before you publish, because the addon tags what you publish with that task. ## Where does Dousen save its data? Convention tags and the material assignment are stored as file properties (`dousen_convention_tags` and `dousen_material_assignment`), and the auto-publish setting on the root node, so they travel with the scene in Perforce. The Dousen menu also has Send to Substance Painter when Painter was connected at startup. It exports the selected objects as an FBX file and sends it to Painter. ## How does 3ds Max show Perforce status? The Perforce tab shows lock state and the Check Out, Sync & Reload, Revert and Refresh actions. Publishing checks for other users’ locks before it exports. See Dousen + Perforce. ## Related - 3ds Max in DCC addons - DCC validation coverage - Dousen + Maya Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Blender — Dousen URL: https://dousen.io/integrations/blender.html Summary: How the Dousen Blender addon works: the Dousen sidebar tab, Collection-based instances, validation, publishing to Unreal, auto-publish on save and Perforce status. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for Blender adds a Dousen tab to the 3D Viewport sidebar. Each top-level Collection that contains a mesh becomes an instance, which you validate and publish to Unreal as FBX. It also supports auto-publish on save and shows Perforce file status for the open .blend file. - Load: launch Blender from the apps bar in DousenDesktop; nothing to install. - Panel: press N over the 3D Viewport and select the Dousen tab. - Exports: one FBX per instance, including an armature for skeletal meshes. - Validation: Run Validation blocks publishing on errors; Fix appears for rules that offer one. - Perforce: the File Status (P4) sub-panel. ## How does the addon load? DousenDesktop ships the addon. When you launch Blender from the apps bar (check the path in Settings → DCC Apps), Desktop loads it and passes the project, task and sign-in details. A Blender started from a desktop shortcut has no Dousen panel. After you update DousenDesktop, restart Blender. ## What becomes an instance? Each top-level Collection that contains a mesh. Objects directly in the Scene Collection aren’t collected. To create your own instance, add a custom property named `dousen_instance` to a Collection at any depth. If its value is text, that text becomes the instance name. Click Refresh Instances to list them; each has a checkbox saved on the Collection. ## What does the panel show? | Sub-panel | Controls | |---|---| | Dousen | Refresh Instances, Publish Checked Instances and the Auto-publish on Save toggle. | | Validation | Run Validation, with results by category and Fix where available. | | New Asset | Set Up Asset saves the .blend to the path your conventions resolve and adds it to the task’s changelist. | | Materials | Refresh Material Catalog and Auto-Fill Textures assign catalog materials per slot. | | File Status (P4) | Check Out Source, Sync & Reload, Revert Checkout, Refresh. | ## How do I validate and publish? - Press N, open the Dousen tab and click Refresh Instances. - Check the instances to publish. - Open Validation and click Run Validation. Fix errors, using Fix on the frozen-transform rules. - Click Publish Checked Instances. Errors stop the publish. Warnings also stop it unless you select Publish despite validation warnings. - Watch Publish history in DousenDesktop for Imported and saved in Unreal. An animation instance exports its own objects and rig to FBX, like a mesh instance. Before export, Dousen writes convention tags to the exported objects as custom properties. ## Can Blender publish on save? Yes. Turn on Auto-publish on Save in the Dousen panel. Each save then publishes the checked instances, one `mesh.export` event per instance. A save-triggered publish doesn’t run the validators, though it still checks instance names if your naming rule is set to error. The setting is stored in the scene as `dousen_auto_publish`. ## Where does Dousen save its data? Convention tags, the material assignment and the auto-publish setting live in your .blend file as scene properties (`dousen_convention_tags`, `dousen_material_assignment` and `dousen_auto_publish`), so they travel with the file in Perforce. If Substance Painter is connected, Send to Substance Painter exports the selected objects as an FBX file next to the .blend file and sends it to Painter. ## How does Blender show Perforce status? The File Status (P4) sub-panel shows the lock state of the current .blend file, and only the button that applies appears. Before any publish exports, Dousen checks for locks held by other users and stops if it finds one. See Dousen + Perforce. ## Related - Blender in DCC addons - Asset validation - Dousen + Unreal Engine 5 - Dousen + Maya Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Houdini — Dousen URL: https://dousen.io/integrations/houdini.html Summary: How the Dousen Houdini addon works: the Dousen shelf, geo-node instances, HDA, VAT and Alembic export tools, validation, auto-publish and Perforce status. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for Houdini adds a Dousen shelf instead of a panel. Each geo node directly under /obj is an instance, and the shelf tools export HDAs, vertex animation textures and Alembic files to Unreal, publish them through DousenDesktop, and show Perforce lock status. - Load: launch Houdini from the apps bar in DousenDesktop. - Controls: the Dousen shelf; Houdini has no Dousen panel. - Exports: HDA, VAT (mesh and textures) and Alembic, plus FBX for auto-publish. - Perforce: shelf tools for status, checkout, sync and revert. - Auto-publish: no toggle; a studio script sets `dousen_auto_publish` user data on /obj. ## How does the addon load? DousenDesktop ships the addon and loads it when you launch Houdini from the apps bar. The shelf tool Dousen: Send to Painter appears only if Substance Painter was connected when Houdini loaded the addon. ## What becomes an instance? Each `geo` node directly under `/obj`, unless a node inside it has the `dousen_instance` user data. To make your own instance, add that user data to a node. If its value is text, that text becomes the instance name. ## What do the shelf tools do? | Shelf tool | What it does | |---|---| | Dousen: Export HDA | Saves the selected node’s HDA to the HDAs folder under the source root and publishes it as `mesh.export`. | | Dousen: Export VAT | Renders the selected ROP network set up for vertex animation textures and publishes textures and mesh together. | | Dousen: Export Alembic | Exports the selected node to the Alembic folder and publishes it as `mesh.export`. | | Dousen: Material Setup | Picks one catalog material for the whole asset. | | Dousen: Send to Unreal | Does the same as Dousen: Export VAT. | ## How does validation work in Houdini? Run Dousen: Validate before you export. It prints results to the console and has no Fix buttons. The three export tools don’t validate, so an error doesn’t stop them. If the scene isn’t tagged, validation infers the asset type from the saved file path. Houdini’s HDA and VAT rules are listed in Asset validation. ## Can Houdini publish on save? There’s no toggle in the interface. A studio script can set the `dousen_auto_publish` user data on `/obj` to `1`. Each save then exports one FBX and publishes one `mesh.export` event per instance, or `animation.export` for an animation instance. A save-triggered publish doesn’t run the validators, though it still checks instance names, so a naming rule set to error can stop it. ## Where does Dousen save its data? Houdini has no material picker panel. Dousen: Material Setup opens a dialog where you choose one catalog material for the whole asset. The assignment travels with the export to Unreal. Convention tags, the material assignment and the auto-publish setting are stored as user data on `/obj` (`dousen_convention_tags`, `dousen_material_assignment` and `dousen_auto_publish`), so they travel with the .hip file. When another application sends a mesh to Houdini, Dousen creates a `geo` node with a file SOP inside it. ## How does Houdini show Perforce status? The shelf has Dousen: File Status (P4), Dousen: Check Out, Dousen: Sync & Reload and Dousen: Revert Checkout. The export tools and auto-publish run the Perforce pre-flight: if another user holds a lock on a file, the publish stops and names the lock. Otherwise Dousen opens the files for edit in the task’s changelist. See Dousen + Perforce. ## Related - Houdini in DCC addons - Houdini validation rules - Dousen + Unreal Engine 5 Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Integrations — Dousen URL: https://dousen.io/integrations/index.html Summary: Dousen integrations for Jira Cloud, Perforce, Unreal Engine 5.7 and 5.8, Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer. By Luca Vitiello · Updated 6 October 2026 Dousen integrates with Jira Cloud, Perforce, Unreal Engine 5.7 and 5.8, and six DCC applications: Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer. Each page below says what the integration does, where it appears in the tool and which part of the documentation covers setup. Dousen connects Jira Cloud, Perforce, six DCC applications and Unreal Engine 5.7 and 5.8 around one task. Pick the tool you use to see what the integration does and how to set it up. Each page links to the full documentation. Dousen + Jira CloudYour task list from Jira Cloud, changelists linked to the issue key, and a transition on submit. Dousen + PerforceOne changelist per task, file locks in your DCC, streams, workspace setup and separate source repositories. Dousen + Unreal Engine 5The DousenUE plugin, Interchange import, naming on import, reimport, Open in DCC and the material catalog. Dousen + BlenderA Dousen sidebar tab, Collection instances, validation, publishing and auto-publish on save. Dousen + MayaA shelf and docked panel, group instances, validation, publishing and auto-publish on save. Dousen + 3ds MaxThe docked panel for 3ds Max 2025 or later, node instances, selection sets and publishing. Dousen + HoudiniShelf tools for HDA, VAT and Alembic export, geo-node instances and Perforce status. Dousen + Substance PainterTexture-set instances, a material picker, texture publishing and publish on save. Dousen + Substance DesignerGraph instances, baking, .sbsar export and a per-graph material picker. ## How do the integrations fit together? An artist selects a Jira task in DousenDesktop, which opens a Perforce changelist for it. The DCC addon collects, validates and publishes instances under that task. The DousenUE plugin imports them into Unreal with your naming conventions. Submitting the changelist can move the Jira issue. Setup starts in the Quick start. ## Related - Documentation - What each DCC addon can do Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Jira Cloud — Dousen URL: https://dousen.io/integrations/jira.html Summary: How Dousen connects to Jira Cloud: your task list in DousenDesktop, changelists linked to the issue key, and an optional Jira transition when you submit. By Luca Vitiello · Updated 6 October 2026 Dousen connects to Jira Cloud in two ways. DousenDesktop reads your assigned issues with your own email and API token and shows them as the My tasks list. DousenCore uses a project-level connection to move the issue to a new status when you submit the task’s Perforce changelist. - Jira Cloud only; Jira Cloud is the task system; Dousen keeps no tracker of its own. - Task list: `GET /rest/api/3/search/jql`, 50 issues per page, refreshed every 30 seconds by default. - Panel location: the My tasks tab in DousenDesktop. - Credentials: your email and API token under Settings → Jira. - Transition on submit: the `jira.on_submit_transition` pipeline setting. ## How does Dousen list my Jira tasks? You enter your Jira Cloud base URL, email and an Atlassian API token in Settings → Jira. DousenDesktop calls Jira directly from your machine with those credentials, so you see the issues you can see in Jira. The tab lists issues with this JQL: ``` assignee=currentUser() AND statusCategory != Done ``` Select a task to see its description as Jira renders it. The detail pane has these controls. | Button | Action | |---|---| | Open in Jira | Opens the issue in your browser. | | Open changelist | Opens a Perforce changelist for the issue. | | Submit changes | Submits the linked changelist. | | Restore shelved changes | Unshelves the last shelved changelist for the task (preview). | ## How is a changelist linked to a Jira issue? Click Open changelist on a task. Dousen creates a Perforce changelist whose description starts with the issue key, such as `DOU-142`, and records it in DousenCore under that key. While the task stays selected, every connected DCC addon receives the task and changelist, and your exports carry them. The key stays in the submitted changelist description, so it remains in the depot history. See Dousen + Perforce for the changelist workflow. ## Can Dousen move the issue when I submit? Yes. A project admin adds the project’s Jira connection in the web portal (Jira Configuration in Project settings: base URL, project key, email and API token). The admin then names the transition in the Jira transition on CL submit pipeline setting: ``` jira: on_submit_transition: "In Review" ``` After a successful submit, DousenCore lists the issue’s transitions, picks the one whose name matches the setting (ignoring case) and runs it. Use the name of the workflow transition, which can differ from the status it leads to. If no transition matches, the submit still succeeds and the issue stays where it is. Saving or publishing an asset never changes the issue. If the project uses a separate source repository, the issue moves after the last non-empty changelist is submitted. ## What isn’t supported? - Jira Data Center and Jira Server. The setup is documented for Jira Cloud sites only. - Storing or editing tasks in Dousen. Create and edit issues in Jira. - Moving the issue on save or publish. Only a submitted changelist triggers the transition. If Jira is slow or unreachable, DousenDesktop keeps showing the last known tasks. If Jira rejects your credentials, polling stops until you save valid ones. DousenCore also accepts signed Jira webhook events at `POST /webhooks/jira`, but the endpoint doesn’t change any task or changelist state. ## Related - Jira tasks in the documentation - The My tasks tab - Dousen + Perforce Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Maya — Dousen URL: https://dousen.io/integrations/maya.html Summary: How the Dousen Maya addon works: the Dousen shelf and docked panel, instances from groups and export sets, validation, publishing, auto-publish on save and Perforce status. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for Maya opens a Dousen shelf and a docked panel at startup. Each top-level group or mesh transform that contains a mesh becomes an instance. You validate and publish checked instances to Unreal as FBX from the Publish tab, with optional auto-publish on save and Perforce status in the panel. - Load: launch Maya from the apps bar in DousenDesktop. - Panel: docked, with tabs Publish, Perforce, New Asset, Materials and Tools. - Exports: one FBX per instance with the project’s `export_presets.maya` settings; skinned meshes include their skeleton. - New Asset saves a `.ma` file to the path your conventions resolve. - Panel shared with 3ds Max, Substance Painter and Substance Designer. ## How does the addon load? DousenDesktop ships the addon and loads it when you launch Maya from the apps bar. Maya starts with a Dousen shelf and the docked panel. The shelf also has Dousen Validate, which opens the Publish tab, and Dousen Asset. Maya started from a desktop shortcut has no panel. ## What becomes an instance? Each top-level group or mesh transform that contains a mesh, and each DousenClips clip if DousenClips is installed. To build your own, select objects and click + Instance from Selection, or add a `dousenInstance` attribute to an object set. If an export set holds only part of a group, put the group’s other children in their own set, or they aren’t published. ## How do I validate and publish? - Open the Publish tab. Click Reset after you change the scene. - Check the instances to publish. Right-click one and choose Set Type if its type is wrong. - Click Validate. Use Select Invalid to select failing objects and Repair where a rule offers a fix. - Click Publish. Errors stop it. If only warnings remain, Dousen asks N warning(s) found. Publish anyway? - Check Publish history in DousenDesktop. ## What else is in the panel? | Tab | What it does | |---|---| | New Asset | Load Conventions, choose a name, type and taxonomy, then Set Up Asset saves the scene and adds it to the task’s changelist. | | Materials | The catalog material picker, one material per slot. | | Tools | Send to Painter while Substance Painter is connected, and the Publish mesh.export on save checkbox. | | Perforce | File status, Check Out, Sync & Reload, Revert and Refresh. | ## Can Maya publish on save? Yes. Check Publish mesh.export on save on the Tools tab. Each save publishes the checked instances, one `mesh.export` event per instance, or `animation.export` for an animation instance. It doesn’t run the validators, though it still checks instance names, so a naming rule set to error can stop it. The setting is stored in the scene, so check it when you open a different file. ## How does Maya show Perforce status? The Perforce tab shows the scene’s lock state and offers the actions that apply. The panel header shows the current task and the Perforce stream, or `Classic depot`. See Dousen + Perforce. ## Related - Maya in DCC addons - Asset validation - Dousen + 3ds Max - Dousen + Unreal Engine 5 Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Perforce — Dousen URL: https://dousen.io/integrations/perforce.html Summary: How Dousen uses Perforce: one changelist per Jira task, file locks inside your DCC, stream detection, workspace creation in the setup wizard, and separate source repositories. By Luca Vitiello · Updated 6 October 2026 Dousen opens one Perforce changelist per Jira task, runs `p4` under your own user and workspace, and shows file locks, checkout, sync and revert inside Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer. It detects streams automatically and can create your workspace from a project’s depot path. - DousenDesktop runs `p4` on your workstation; DousenCore doesn’t need access to your Perforce server for current DousenDesktop builds. - One changelist per task. Submit needs a message of at least 5 characters. - DCC panels refresh lock status about every 30 seconds with `p4 fstat`. Houdini uses shelf tools on demand instead. - Streams are detected from `p4 info`; nothing to configure. - Projects can bind a second Perforce server for DCC source art. ## How does Dousen use changelists? Select a Jira task in DousenDesktop and click Open changelist. Desktop creates a numbered changelist in your workspace and reports the number to DousenCore, which keys it to the issue. If the task already has an open changelist, Desktop reuses it. Exports from any DCC addon go to that changelist. To finish, click Submit changes, enter a message in the Submit Changelist dialog and submit. The submit fails if the changelist has no opened files, because Desktop never moves files out of the default changelist. ## What does the DCC panel show about locks? Each addon shows the Perforce status of the current scene and lets you check it out (`p4 edit`), sync and revert. New files are marked for add automatically by New Asset and by a publish. Houdini has no refreshing panel. Its Dousen: File Status (P4) shelf tool shows the state on demand. Checkout and add use the active task’s changelist. A publish stops before it exports if another user has locked a file the export would write. | Status line | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open, and your copy is current. | ## Does Dousen support Perforce streams? Yes. Dousen reads the `clientStream` field of `p4 info`. The DousenDesktop status bar shows `P4: ` for a stream workspace or `P4: (classic)` for a classic depot, and the DCC panel shows `Stream: ` or `Classic depot`. ## Can Dousen create my workspace? If your admin has set a `depot_path` on the project, the Workspace step of the setup wizard can do it. Click Check. If a workspace already maps the path, Dousen fills in its root and name. Otherwise choose a local root and workspace name and click Create Workspace. Dousen checks with `p4 streams` whether the path is a stream root and writes a stream workspace or a classic client spec to match. It doesn’t sync anything, so run your first sync from P4V or UnrealGameSync before you open a DCC. ## What if source art lives in a separate repository? A project admin can bind a second Perforce repository, possibly on another server, for DCC source files. Each artist creates a source workspace once in the setup wizard. Narrow client views map only the folders an artist opens, and Dousen syncs files on demand. The task then gets one changelist per repository: Desktop submits the source changelist first, deletes empty ones, and the Jira transition runs after the last submit. A pending changelist on the other server defers the transition. Submits to two servers aren’t atomic, so check both changelists afterward. Texture dependencies aren’t synced automatically. ## Related - Perforce in the documentation - Source repositories - Dousen + Jira Cloud Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Substance Designer — Dousen URL: https://dousen.io/integrations/substance-designer.html Summary: How the Dousen Substance Designer addon works: the docked panel, compositing-graph instances, baking, .sbsar export, the material picker and Perforce status. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for Substance Designer shows a docked panel where each compositing graph in the loaded packages is an instance. You bake and publish the checked graphs to Unreal as texture exports, send a .sbsar file, and assign catalog materials, one per graph. - Load: launch Substance Designer from the apps bar in DousenDesktop; the panel appears as a dock. - Tabs: Publish, Perforce, Export, Materials and Tools. - Formats: TGA textures by default, or `export_presets.substance_designer`; `.sbsar` packages. - Auto-publish on save: not available. - Designer saves tags and material assignments in sidecar files next to the package. ## How does the addon load? DousenDesktop ships the addon and loads it when you launch Substance Designer from the apps bar. When another application sends a mesh to Designer, Designer stores the file path for use in your baking graph; it doesn’t connect the mesh to a node. ## What becomes an instance? Each compositing graph in the loaded packages. You don’t create instances by hand. ## What do the Publish and Export tabs do? | Control | What it does | |---|---| | Publish | Bakes the graphs in each package once, then publishes one `texture.export` event per checked graph with the material assignment. Dousen can’t bake a single graph on its own. | | Export Baked Textures | Renders the graphs and exports textures to the Textures folder under the source root. | | Export .sbsar | Exports the package as a .sbsar file to the Materials folder under the source root. | | Send to Unreal | Runs the validated publish flow for the checked graphs. | | Send .sbsar to Unreal | Exports and publishes the .sbsar file. It doesn’t run if validation reports errors. | ## How do I assign materials? Open the Materials tab, click Load Materials and choose a catalog material for each graph. Bind the textures under Material Details. The Publish tab and Send to Unreal send the assignment, and it also decides whether the Nanite or NonNanite validator category runs. ## How does validation work? Click Publish and Dousen validates the checked graphs first. Designer has graph and naming rules; errors stop the publish and the panel has no built-in fixes. Rules are listed under DCC coverage. ## Where does Dousen save its data? Designer has no metadata store, so Dousen saves convention tags in `.dousen-tags.json` and the material assignment in `.dousen-material.json` next to the package. Unlike the other addons, Designer has no auto-publish on save, so publish from the Publish tab after you save. ## How does Designer show Perforce status? The Perforce tab shows the package’s lock state and offers Check Out, Sync & Reload, Revert and Refresh. Publishing runs the lock check and the naming check before it exports. Check in the `.dousen-tags.json` and `.dousen-material.json` sidecars with the package. See Dousen + Perforce. ## Related - Substance Designer in DCC addons - Materials and textures - Dousen + Substance Painter Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Substance Painter — Dousen URL: https://dousen.io/integrations/substance-painter.html Summary: How the Dousen Substance Painter addon works: the docked panel, texture-set instances, validation, publishing textures to Unreal, the material picker and auto-publish on save. By Luca Vitiello · Updated 6 October 2026 The Dousen addon for Substance Painter shows a docked panel where each texture set in the open project is an instance. You validate and publish the checked texture sets to Unreal as texture exports, assign catalog materials per texture set, and optionally publish on every save. - Load: launch Substance Painter from the apps bar in DousenDesktop; the panel appears as a dock. - Tabs: Publish, Perforce, Export and Tools. - Default texture format: TGA, or the format in `export_presets.substance_painter`. - Textures need a target Unreal mesh. - Publishing runs a Perforce lock check and the naming check first. ## How does the addon load? DousenDesktop ships the addon and loads it when you launch Substance Painter from the apps bar. When another application sends a mesh to Painter, Painter replaces the mesh of the open project, or creates a project from the mesh if none is open. ## What becomes an instance? Each texture set in the open project. Nothing needs to be created by hand. Each checked texture set publishes as its own `texture.export` event. ## What is the target Unreal mesh? Textures need a mesh to land on. If Dousen exported the mesh, Painter reads the target from the mesh’s metadata sidecar. Otherwise, on the Export tab, enter the path in Target Unreal mesh, for example `/Game/Props/S_Crate.S_Crate`, and click Use target mesh. Without a target, validation reports an error named Target Unreal mesh. Meshes can also come to Painter from other applications. Blender, Maya, 3ds Max and Houdini have a Send to Painter action that appears when Painter is connected. The Export tab also has Send to Unreal, which runs the same validation and publish as the Publish tab. ## How do I validate and publish? - Open the Publish tab and check the texture sets to publish. - Assign materials on the Export tab: Load Materials, then choose one per set under Texture Set Materials, and bind textures under Material Details. - Click Publish. Dousen validates the checked sets, exports them to the Textures folder under the source root, and publishes one event per set. - Check Publish history in DousenDesktop. When Dousen starts the export, with Publish or Export Textures, it refuses a format that isn’t in the project’s `texture.allowed_formats` setting and shows the reason in the results. Export Textures exports every set without publishing, and Send to Unreal runs the same flow as Publish. If you use Painter’s own export dialog, Dousen logs a warning for a format outside that list and still publishes each exported file. ## Can Painter publish on save? Yes. Check Publish textures on save on the Tools tab. Each save publishes one `texture.export` event per texture set, which needs a target Unreal mesh. The setting is stored in the project metadata. ## Where does Dousen save its data? Convention tags, the material assignment and the auto-publish setting are stored in the project metadata, in the Dousen namespace, so they travel with the project file. Painter uses the same material picker as the other Qt panels, with one catalog material per texture set under Texture Set Materials. ## How does Painter show Perforce status? The Perforce tab shows the project’s lock state with Check Out, Sync & Reload, Revert and Refresh. Publishing stops if another user has locked a file the export would write. See Dousen + Perforce. ## Related - Substance Painter in DCC addons - Assign a material in the DCC - Dousen + Substance Designer Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. ## Dousen + Unreal Engine 5 — Dousen URL: https://dousen.io/integrations/unreal-engine.html Summary: How Dousen imports published assets into Unreal Engine 5.7 and 5.8 with the DousenUE plugin and Interchange, applies naming conventions, reimports, and opens source files in your DCC. By Luca Vitiello · Updated 6 October 2026 Dousen imports published DCC assets into Unreal Engine 5.7 and 5.8 through the DousenUE plugin and Unreal’s Interchange framework. The plugin names and places each asset from your project conventions, reimports on republish, applies catalog materials, and adds Open in DCC to the Content Browser. - Supported: Unreal Engine 5.7 and 5.8 only (not 5.6 or earlier, not UE4). - Plugin: DousenUE, installed from Settings → Unreal with Install into .uproject. It needs PythonScriptPlugin and Interchange. - Settings: `Config/DefaultDousenUE.ini` in your Unreal project. - The plugin connects to DousenDesktop’s bridge on `localhost`, port 8766 by default. - Desktop shows Imported and saved in Unreal only after the packages are saved. ## How does a published asset get into Unreal? When you publish an instance from a DCC, DousenDesktop records it in Publish history and sends the import to the open editor. If no editor is open and headless import is on, Desktop imports in the background with `UnrealEditor-Cmd`. Dousen works out the asset’s name and folder, imports it with Interchange, applies materials and saves the packages. ## How are assets named on import? The plugin fetches your project’s naming conventions from DousenCore and refreshes them every 5 minutes. Before it creates an asset, Dousen checks the required tag dimensions, allowed values, taxonomy, package name and whether the asset exists. Without conventions it can’t import a new asset. A later reimport never renames an asset. ## What happens when I publish again? Meshes and animations that already exist reimport and keep their asset paths and stored import settings. Meshes you add to the source scene wait for your approval, and meshes you remove stay in the project. Right-click an imported mesh and choose Review instance topology to approve additions. Named geometry profiles from your conventions set options such as collision, normals and Nanite per instance. ## How do I get back to the source file? Select the task, then right-click a static mesh, skeletal mesh or texture in the Content Browser and choose Open in DCC. Desktop finds the source file, syncs it from Perforce if needed, and launches the DCC. If the project uses a separate source repository, Reimport (sync source) syncs the FBX and its sidecar and reimports only the selected asset. ## Can artists pick materials from Unreal? Yes. An admin creates a Dousen Material Catalog Data Asset in the project’s content and sets `MaterialCatalog` in `Config/DefaultDousenUE.ini`. Saving it while signed in to DousenDesktop as an admin reports the catalog to DousenCore. Artists then choose a catalog material per slot in the DCC, and the import binds textures into the material instances. On static meshes it also sets Nanite from the catalog’s Allow Nanite value. Dousen also stamps convention tags and `dousen_cv_*` tags on each asset. You can search them from the Tag Search section of the Dousen tab. ## Related - Unreal Engine in the documentation - Unreal Interchange - Materials and textures - Dousen + Perforce Dousen is free during the studio beta, with access by request, and free forever for teams of up to 5 users. Request early access. # Compare ## Dousen compared: the asset pipeline built for games — Dousen URL: https://dousen.io/compare/index.html Summary: Dousen is the asset pipeline built for games, with nothing to migrate: tasks stay in Jira, files in Perforce, assets in Unreal. Compared with six tools. //dousen/compare — Dousen compared free studio beta # The asset pipeline built for games. On the Jira, Perforce and Unreal you already run. A Jira task opens a Perforce changelist. The asset is checked inside Maya, Blender, 3ds Max, Houdini or Substance (the DCC) before it leaves, then imported into Unreal Engine with the right name and folder. Jira moves when the changelist is submitted. AYON, Prism, Kitsu, Flow Production Tracking and ftrack were built around film and animation production; Anchorpoint around Git. Dousen was built for this. For indie and AA game studios on Perforce, Jira Cloud and Unreal Engine 5.7 or 5.8, with Windows artist workstations. Not a tracker: no review, dailies or scheduling. Request early access Read the docs //dousen/built-for-games ## What a game asset pipeline has to do Dousen is built around four steps, from the Jira task to the submitted changelist. on_task ### One changelist per Jira task The Open changelist button in DousenDesktop creates a numbered changelist for the task and keeps the Jira key in its description. The DCC panel shows `Locked by (CL n)`, and a publish stops before it exports if another user has locked a file it would write. HBR-142 → CL 28471 · Locked by maria (CL 28466) pre_export ### Validation tuned for real-time Validators check triangle budgets, n-gons, non-manifold geometry, lightmap UV overlap, applied transforms, rigs and animation, with Nanite and NonNanite categories. An error blocks the export. A project admin (whoever owns the studio’s pipeline rules) sets them per asset type in the web portal. In Houdini, validation is the manual Dousen: Validate shelf tool. mesh.poly_count 48,210 / 50,000 ✓ · uvs.no_overlap_lightmap ✓ on_publish ### Import into Unreal, named by your conventions Unreal imports the export with Interchange. The asset name and Content Browser folder come from the project conventions, and a reimport keeps existing asset paths. Review instance topology approves new members, and a material catalog with an Allow Nanite flag covers materials. SM_CargoCrate_01.fbx → /Game/Props/Cargo/SM_CargoCrate_01 on_submit ### Jira moves when the changelist submits Submit changes runs `p4 submit` on the task’s changelist. When the project admin has set `jira.on_submit_transition`, the linked Jira issue moves forward. Artists use their own Jira credentials. CL 28471 submitted → HBR-142 In Review The alternatives are built around animation and VFX shots (AYON, Prism), production tracking and review (Kitsu, Flow Production Tracking, ftrack) and Git version control (Anchorpoint). Each is described in its own words below. //dousen/no-migration ## Nothing to migrate, nothing to build around ### With Dousen you add - DousenDesktop, a Windows app that ships the DCC addons (DCC addons) - The DousenUE plugin in your Unreal project - DousenCore, hosted at dousen.io or self-hosted with Docker Compose on Linux (self-hosted install) You keep Jira as the tracker, the Perforce depot as the source of truth and your Unreal project layout. ### What the alternatives add - AYON: a server database, anatomy templates and the Launcher app (anatomy (https://help.ayon.app/articles/3815114-project-anatomy), backend (https://github.com/ynput/ayon-backend)) - Prism: its project folder tree, `00_Pipeline` to `04_Resources` (folder structure (https://prism-pipeline.com/docs/latest/general/folderStructure/)) - Kitsu: the Zou API, web UI, PostgreSQL, Redis and the Publisher app (self-hosted (https://kitsu.cloud/self-hosted/), Publisher (https://github.com/cgwire/kitsu-publisher-next)) - Flow Production Tracking: a hosted entity database, Toolkit, a desktop app and an sg-jira-bridge that you host (tk-core (https://developers.shotgridsoftware.com/tk-core/core.html), sg-jira-bridge (https://developers.shotgridsoftware.com/sg-jira-bridge/)) - ftrack: an entity database, the Connect app and per-DCC plugins (on-premise guide (https://help.ftrack-studio.backlight.co/hc/en-us/articles/13129804449303-Introduction-to-On-Premise)) - Anchorpoint: a Git repository with LFS in place of Perforce (anchorpoint.app (https://www.anchorpoint.app/)) Dousen stores no asset files and no tasks. If you stop using it, everything is where it already was. //dousen/checklist ## Side by side Ten things a game asset pipeline does, and what each product documents about them. Scroll sideways on a narrow screen. Dousen is a Perforce, Jira and Unreal specialist. The other columns were built from each product’s public documentation only, checked 6 October 2026. “Not in public docs” means we found no mention, not that the feature is missing; tell us at hello@dousen.io if we missed it. | | Dousen | AYON | Prism | Kitsu | Flow PT | ftrack | Anchorpoint | |---|---|---|---|---|---|---|---| | One Perforce changelist per Jira task | Numbered changelist per Jira task (Perforce) | `p4 sync`; can commit published versions[1] | Not a replacement for Perforce[2] | Not in public docs | Toolkit Perforce components archived 2024[3] | Perforce location plugin publishes versions[4] | Git with LFS, or Lore[5] | | Shows who has a file locked before you work on it | `Locked by (CL n)`; publish stops (file locks) | Syncs and commits; checkout via P4V per its README[1] | Not in public docs | Not in public docs | Not in public docs | Not in public docs | Unreal plugin shows locked files[6] | | Unreal Engine 5.7/5.8 import through Interchange, named from conventions; reimport keeps the asset path | Interchange import, names from conventions (Unreal) | `/Content/AYON/` mirror, version folders[7] | Imports FBX; Interchange not described[2] | Publisher sends previews; no import[8] | tk-unreal; Interchange not described[9] | Imports Alembic, FBX; listed Deprecated[10] | Version control only; no import described[6] | | Jira Cloud as the task system (artists’ own credentials, transition on submit) | Jira Cloud, personal credentials, transition on submit (Jira) | Own tracker; Jira addon is one-way[11] | Own backend; Jira not mentioned[12] | Own tracker; Jira is a feature request[13] | Own tracker; sg-jira-bridge you host[14] | Not in public docs | Python Jira integration syncs Epics[15] | | Naming enforced in every DCC and on Unreal import, from one YAML/Lua document | One YAML or Lua document (conventions) | Anatomy templates set paths[16] | Folder Structure templates, Python expressions[17] | Not in public docs | `templates.yml` tokens, folder schema[18] | Not in public docs | Name templates applied at creation[19] | | Real-time validation before export (triangle budgets, lightmap UVs, Nanite categories) | Ready-made checks, set in the portal (validation) | Pyblish; all validators must pass[20] | Pre-publish hooks possible[21] | Not in public docs | publish2 validate gate; studio hooks[22] | Not in public docs | Not in public docs | | What the tool adds that you then work around | Files stay in Perforce, tasks in Jira (self-hosted) | Own server database[16] | Fixed project folder tree[17] | Own entity database[30] | Hosted entity database[18] | Own entity database[31] | A Git or Lore repository[32] | Competitor cells quote each product’s public documentation, checked 6 October 2026; numbers link to Sources below. Corrections: hello@dousen.io. //dousen/alternatives ## The alternatives, in their own words ### AYON AYON keeps projects, folders, tasks, products and versions in its own server database, with anatomy templates for workfile and publish paths (anatomy (https://help.ayon.app/articles/3815114-project-anatomy)). Its Perforce addon syncs with `p4 sync` and commits published versions; its README says artists check out with P4V or the Unreal Perforce plugin, and it does not describe file locks (ayon-perforce (https://github.com/ynput/ayon-perforce)). The Unreal addon creates a `/Content/AYON/` mirror with `{product_name}_{version}` folders (Unreal addon (https://help.ayon.app/articles/0086198-about-unreal-addon)), and the Jira addon is one-way from AYON to Jira (ayon-jira (https://github.com/ynput/ayon-jira)). AYON is built for animation and VFX pipelines: Pyblish validation stops a publish until all validators pass (pipeline (https://help.ayon.app/articles/7070980-about-ayon-pipeline)), and its pricing page addresses animation and VFX studios (pricing (https://ayon.app/pricing-eur)). ### Prism Pipeline Prism stores a project as a file-based folder tree with no server or database (installation (https://prism-pipeline.com/docs/latest/general/installation/)), laid out from `00_Pipeline` to `04_Resources` (folder structure (https://prism-pipeline.com/docs/latest/general/folderStructure/)). Its Unreal page says Prism is not a replacement for Perforce; the plugin imports Alembic, USD, FBX and OBJ and brings shots into Sequencer, and naming of imports and Interchange are not described (Unreal Engine (https://prism-pipeline.com/docs/latest/plugins/Unreal%20Engine/)). Tasks use a built-in backend or ftrack, Kitsu or ShotGrid (project management (https://prism-pipeline.com/docs/latest/plugins/Project%20Management/)). Prism is built for animation and VFX projects (docs (https://prism-pipeline.com/docs/latest/)); its core and ten plugins are LGPL v3, and it runs as a desktop app on Windows, Linux and macOS (licensing (https://prism-pipeline.com/docs/latest/general/licensing/)). ### Kitsu Kitsu keeps projects, assets, shots, tasks and previews in its own entity database, served by the Zou API (kitsu.cg-wire.com (https://kitsu.cg-wire.com/)). Kitsu Publisher sends previews from the tools, including from Unreal on UE 5 and later; no asset import is described (Publisher (https://github.com/cgwire/kitsu-publisher-next)). Its documentation does not describe version control, and the REST API, webhooks and gazu client are the route for custom integration (custom integration (https://www.cg-wire.com/faq/custom-integration/)). A Jira integration is a feature request on its Canny board (Canny (https://cgwire.canny.io/integration)). Kitsu is built for production tracking: it is an open-source tracker under AGPL-3.0 with review and scheduling, and it names game studios on its homepage (cg-wire.com (https://www.cg-wire.com/kitsu/)). ### Flow Production Tracking Flow, formerly ShotGrid, keeps projects and entities in a hosted database, and Toolkit’s `templates.yml` and folder schema map file paths to them (tk-core (https://developers.shotgridsoftware.com/tk-core/core.html)). The Toolkit Perforce components were archived on GitHub in September 2024 (tk-framework-perforce (https://github.com/shotgunsoftware/tk-framework-perforce)). tk-unreal exposes publish2 and loader components in the editor; Interchange and naming of imports are not described (tk-unreal (https://github.com/shotgunsoftware/tk-unreal)). sg-jira-bridge adds two-way Jira sync that you host as a web app, an event daemon and a Jira webhook (sg-jira-bridge (https://developers.shotgridsoftware.com/sg-jira-bridge/)). Flow is built for production tracking across VFX, animation and games (autodesk.com (https://www.autodesk.com/campaigns/film-tv)), and its publish2 validate stage disallows publishing when `validate()` returns False, with the checks defined by the studio’s hooks (publish2 (https://developers.shotgridsoftware.com/tk-multi-publish2/customizing.html)). ### ftrack ftrack stores AssetVersion, Component and ComponentLocation records in an entity database (publishing files (https://developer.ftrack.com/publishing-files/publish/index.html)). A Perforce Helix Core location plugin publishes ftrack versions into Perforce; changelist and checkout behaviour are not described in the pages cited (ftrack-perforce-location (https://ftrack-perforce-location.readthedocs.io/en/latest/)). ftrack-connect-unreal-engine imports Alembic and FBX published from other DCCs, on Windows 10 with UE 5 and later (Unreal docs (https://ftrack-connect-unreal-engine.readthedocs.io/en/latest/)), and the help centre lists the integration under Deprecated (help centre (https://help.ftrack-studio.backlight.co/hc/en-us/articles/13130003888023-Unreal-Deprecated)). ftrack is built for production tracking in film, animation and games (press release (https://www.prnewswire.com/news-releases/perforce-and-ftrack-partner-to-accelerate-creative-production-workflows-in-film-animation-and-video-game-industries-301106503.html)), and runs as hosted SaaS or on-premise (on-premise guide (https://help.ftrack-studio.backlight.co/hc/en-us/articles/13129804449303-Introduction-to-On-Premise)). ### Anchorpoint Anchorpoint organises a project folder backed by a Git repository or Lore, with attributes and tags on files (docs (https://docs.anchorpoint.app/)). Version control goes through GitHub, GitLab, Azure DevOps or Gitea with LFS and file locking; it documents Perforce-to-Git migration (anchorpoint.app (https://www.anchorpoint.app/), blog (https://www.anchorpoint.app/blog/perforce-alternative-for-game-development)). Its Unreal plugin shows locked, modified and obsolete files, submits from the editor and resolves conflicts (Unreal docs (https://docs.anchorpoint.app/git/unreal/)). A Jira integration syncs Jira Epics with folders (jira-integration (https://github.com/Anchorpoint-Software/jira-integration)). Anchorpoint is built for Git version control for game developers: artist-friendly Git with locking, an in-editor Unreal plugin, and no server of its own (anchorpoint.app (https://www.anchorpoint.app/)). //dousen/scope ## What Dousen doesn’t do - No review or dailies tools, no playlists and no media annotation. - No scheduling or resource planning. - No shot or sequence tracking. - No render management. Dousen is the automation between the DCC, Perforce, Jira and Unreal; studios keep their tracker for everything else. //dousen/faq ## Questions studios ask ### Is Dousen a ShotGrid or Flow Production Tracking alternative? Not a tracker replacement. If your studio already tracks tasks in Jira, Dousen is the pipeline layer around them: one changelist per task, validation before export, import into Unreal, the issue moved on submit. It does no review, scheduling or shot tracking, so a studio that needs those keeps its tracker and runs Dousen next to it. ### Does Dousen replace Jira, Perforce or Unreal’s own tools? No. Dousen drives them: it opens the changelist in Perforce, reads the task from Jira Cloud and imports through Unreal’s Interchange framework. Tasks stay in Jira, files in the depot and assets in the Unreal project. ### Can we run Dousen alongside any of these tools? Dousen has no integration with AYON, Prism Pipeline, Kitsu, Flow Production Tracking, ftrack or Anchorpoint, and shares no data with them. It reads tasks from Jira Cloud and changelists from Perforce, so the two can run side by side without exchanging anything. ### Which DCCs and engine versions does Dousen support? Addons for Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer (DCC addons), and the DousenUE plugin for Unreal Engine 5.7 and 5.8 (Unreal Engine). ### What does it cost? Free during the studio beta, access by request. Free forever for teams of up to 5 users; pricing for larger teams has not been announced. //dousen/early-access ## Request early access Dousen is in free beta for pilot studios, built by one founder who works directly with each of them. Your assets stay in Perforce and your tasks in Jira, so you can remove Dousen at any point without losing anything. Keep Jira and Perforce; add the pipeline. Email hello@dousen.io or request access. Request early access Download DousenDesktop //dousen/sources AYON, Prism Pipeline, Kitsu, Flow Production Tracking, ShotGrid, ftrack and Anchorpoint are trademarks of their respective owners. Dousen is not affiliated with, endorsed by or sponsored by any of them; their names are used only to identify the products compared. Product details come from each product’s public documentation as of 6 October 2026; check its site for current information. Pages cited: - AYON: github.com/ynput/ayon-perforce (https://github.com/ynput/ayon-perforce) - Prism Pipeline: prism-pipeline.com/docs/latest/plugins/Unreal%20Engine/ (https://prism-pipeline.com/docs/latest/plugins/Unreal%20Engine/) - github.com/shotgunsoftware/tk-framework-perforce (https://github.com/shotgunsoftware/tk-framework-perforce) - ftrack: ftrack-perforce-location.readthedocs.io/en/latest/ (https://ftrack-perforce-location.readthedocs.io/en/latest/) - Anchorpoint: www.anchorpoint.app/ (https://www.anchorpoint.app/) - Anchorpoint: docs.anchorpoint.app/git/unreal/ (https://docs.anchorpoint.app/git/unreal/) - AYON: help.ayon.app/articles/0086198-about-unreal-addon (https://help.ayon.app/articles/0086198-about-unreal-addon) - Kitsu: github.com/cgwire/kitsu-publisher-next (https://github.com/cgwire/kitsu-publisher-next) - github.com/shotgunsoftware/tk-unreal (https://github.com/shotgunsoftware/tk-unreal) - ftrack: help.ftrack-studio.backlight.co/hc/en-us/articles/13130003888023-Unreal-Deprecated (https://help.ftrack-studio.backlight.co/hc/en-us/articles/13130003888023-Unreal-Deprecated) - AYON: github.com/ynput/ayon-jira (https://github.com/ynput/ayon-jira) - Prism Pipeline: prism-pipeline.com/docs/latest/plugins/Project%20Management/ (https://prism-pipeline.com/docs/latest/plugins/Project%20Management/) - Kitsu: cgwire.canny.io/integration (https://cgwire.canny.io/integration) - Flow Production Tracking: developers.shotgridsoftware.com/sg-jira-bridge/ (https://developers.shotgridsoftware.com/sg-jira-bridge/) - Anchorpoint: github.com/Anchorpoint-Software/jira-integration (https://github.com/Anchorpoint-Software/jira-integration) - AYON: help.ayon.app/articles/3815114-project-anatomy (https://help.ayon.app/articles/3815114-project-anatomy) - Prism Pipeline: prism-pipeline.com/docs/latest/general/folderStructure/ (https://prism-pipeline.com/docs/latest/general/folderStructure/) - Flow Production Tracking: developers.shotgridsoftware.com/tk-core/core.html (https://developers.shotgridsoftware.com/tk-core/core.html) - Anchorpoint: docs.anchorpoint.app/docs/asset-management/templates/ (https://docs.anchorpoint.app/docs/asset-management/templates/) - AYON: help.ayon.app/articles/7070980-about-ayon-pipeline (https://help.ayon.app/articles/7070980-about-ayon-pipeline) - Prism Pipeline: prism-pipeline.com/docs/latest/gettingStarted/insideDCCs/ (https://prism-pipeline.com/docs/latest/gettingStarted/insideDCCs/) - Flow Production Tracking: developers.shotgridsoftware.com/tk-multi-publish2/customizing.html (https://developers.shotgridsoftware.com/tk-multi-publish2/customizing.html) - AYON: help.ayon.app/ (https://help.ayon.app/) - Prism Pipeline: prism-pipeline.com/docs/latest/general/licensing/ (https://prism-pipeline.com/docs/latest/general/licensing/) - ftrack: github.com/ftrackhq/integrations (https://github.com/ftrackhq/integrations) - AYON: github.com/ynput/ayon-backend (https://github.com/ynput/ayon-backend) - Prism Pipeline: prism-pipeline.com/docs/latest/general/installation/ (https://prism-pipeline.com/docs/latest/general/installation/) - Kitsu: kitsu.cloud/self-hosted/ (https://kitsu.cloud/self-hosted/) - ftrack: help.ftrack-studio.backlight.co/hc/en-us/articles/13129804449303-Introduction-to-On-Premise (https://help.ftrack-studio.backlight.co/hc/en-us/articles/13129804449303-Introduction-to-On-Premise) - Kitsu: kitsu.cg-wire.com/ (https://kitsu.cg-wire.com/) - ftrack: developer.ftrack.com/publishing-files/publish/index.html (https://developer.ftrack.com/publishing-files/publish/index.html) - Anchorpoint: docs.anchorpoint.app/ (https://docs.anchorpoint.app/) - AYON: ynput.io/ayon/pricing/ (https://ayon.app/pricing-eur) - Prism Pipeline: prism-pipeline.com/docs/latest/ (https://prism-pipeline.com/docs/latest/) - Kitsu: www.cg-wire.com/faq/custom-integration/ (https://www.cg-wire.com/faq/custom-integration/) - Kitsu: www.cg-wire.com/kitsu/ (https://www.cg-wire.com/kitsu/) - Flow Production Tracking: www.autodesk.com/campaigns/film-tv (https://www.autodesk.com/campaigns/film-tv) - ftrack: ftrack-connect-unreal-engine.readthedocs.io/en/latest/ (https://ftrack-connect-unreal-engine.readthedocs.io/en/latest/) - ftrack: www.prnewswire.com/news-releases/perforce-and-ftrack-partner-to-accelerate-creative-production-workflows-in-film-animation-and-video-game-industries-301106503.html (https://www.prnewswire.com/news-releases/perforce-and-ftrack-partner-to-accelerate-creative-production-workflows-in-film-animation-and-video-game-industries-301106503.html) - Anchorpoint: www.anchorpoint.app/blog/perforce-alternative-for-game-development (https://www.anchorpoint.app/blog/perforce-alternative-for-game-development) # Documentation ## Bridge API — Dousen URL: https://dousen.io/docs/bridge-api.html Summary: Reference for the local Dousen bridge: connect with the Python client, register a tool, publish events, and receive them. Updated October 2026 · Studio developers Describes the local bridge that connects DousenDesktop, the DCC addons and the Unreal plugin on one workstation, and how a studio tool can register with it, publish events and receive them. The bridge is an authenticated RPyC service inside DousenDesktop. It listens on `127.0.0.1`, port `8766` by default, so only programs on the same machine can reach it. Clients send string-keyed requests and receive events over a long-lived push stream. The bridge doesn’t use HTTP. The `dousen.bridge.BridgeClient` Python class that ships with Desktop handles both. For data on the studio server, use the DousenCore REST API. ## Check the normal workflow first Before you test your tool, check that a normal publish works on the same workstation. Artists publish from the DCC panels described in Publishing assets. - Start Desktop, sign in, and select the project. Launch a supported DCC from Desktop, and start Unreal Editor with the DousenUE plugin enabled. - In the Publish history tab, check that the DCC and Unreal appear under Connected apps. - Publish one instance from the DCC and wait for Imported and saved in Unreal. - Run your tool. After it publishes, check Publish history and the asset in Unreal. ## Connect and authenticate `BridgeClient()` connects to `127.0.0.1` on the port in `DOUSEN_BRIDGE_PORT`, or on `8766` if the variable isn’t set. You can pass an address instead, such as `rpyc://127.0.0.1:8766` or a loopback host and port. The client raises an error for any other host. Every request carries a bridge token, which is separate from the DousenCore bearer token. Each time Desktop starts, it generates a new 64-character token and saves it in a `bridge.token` file that only the current user can read. Desktop deletes the file when the bridge stops. | System | Token file | |---|---| | Windows | `%APPDATA%\Dousen\DousenDesktop\bridge.token` | | Linux | `~/.local/share/Dousen/DousenDesktop/bridge.token`, or under `$XDG_DATA_HOME` if it is set | | macOS | `~/Library/Application Support/Dousen/DousenDesktop/bridge.token` | The client reads the token again for every request, so your tool keeps working after Desktop restarts with a new token, unless you set `DOUSEN_BRIDGE_TOKEN`. Don’t copy the token into scripts or documentation. | Environment variable | What it does | |---|---| | `DOUSEN_BRIDGE_PORT` | The bridge port. The default is `8766`. | | `DOUSEN_BRIDGE_TOKEN` | The bridge token. If it is set, the client uses it as is instead of reading `bridge.token`, so it stops working when Desktop restarts with a new token. | | `DOUSEN_PYTHON_PATH` | Set for the tools that Desktop launches. It is the folder to add to `sys.path` for the `dousen` package. | | `DOUSEN_RPYC_PYTHON_PATH` | The folder that contains your own copy of `rpyc`, if you don’t use the one in the Desktop package. | ## Python client example This example registers a tool called `studio_tool`, lists the connected apps, and closes the connection. It needs the `dousen` package and `rpyc` 6.0.1. The package that ships with Desktop includes `rpyc`. PYTHON`from dousen.bridge import BridgeClient with BridgeClient() as bridge: if not bridge.register("studio_tool", "Studio Tool"): raise RuntimeError("Bridge registration failed") apps = bridge.list_apps() print([app["app_id"] for app in apps])` `HttpBridgeClient` is an alias for `BridgeClient` that keeps old imports working. It uses RPyC too. ## Client methods | Method | What it does | |---|---| | `register(app_id, name='', **capabilities)` | Registers your app and returns `True` or `False`. Extra keyword arguments, such as `command_port`, are sent as request fields. A registration expires after 90 seconds, so register again within that time. `subscribe` and `subscribe_async` do this every 10 seconds. | | `deregister(app_id=None)` | Removes a registration by sending `unregister`. Without an argument, it uses the ID from your last successful `register`. It returns nothing and doesn’t raise an error if Desktop can’t be reached. | | `list_apps()` | Returns a list of dictionaries with `app_id` and `subscription_count` (always 0) for the apps in Desktop’s app list and the apps registered over the bridge. The list is empty if the bridge can’t be reached. | | `publish(event_type, source_app, file_path, target_app='', metadata=None, task_id='', changelist_id='', event_id=None)` | Publishes one event. Copies `task_id` and `changelist_id` into `metadata`, and sets `metadata["event_id"]` to the `event_id` argument, to the `event_id` already in `metadata`, or to a random UUID, in that order. Returns `False` if Desktop rejects the event or the request fails. See Limits and failure handling before you publish again. | | `subscribe(subscriber_app, event_type_filter='', on_event=None)` | Registers your app, opens the event stream, and blocks until `stop()` or `close()` is called from another thread. | | `subscribe_async(subscriber_app, event_type_filter='', on_event=None, reconnect=True)` | Runs `subscribe` on a background thread. The stream reconnects if it drops, whatever the value of `reconnect`. | | `wait_until_connected(timeout=5)` | Waits until the event stream is connected and returns `True` or `False`. A registration doesn’t mean the stream is connected. | | `request(operation, payload=None, timeout=None)` | Sends one request and returns the response body. The default timeout is 15 seconds. For any status other than 2xx, it raises `BridgeError`, which carries the status and the response body. See Read an error response. | | `stop()` / `close()` | `stop()` ends the subscription. `close()` calls `deregister()` and then `stop()`. The `with` statement calls `close()` when the block ends. | ## Receive events PYTHON`from dousen.bridge import BridgeClient bridge = BridgeClient() def on_event(event): # Queue work onto the host application's main thread. # Don't call Maya, Blender or Houdini scene APIs from this callback. print(event.event_type, event.file_path) bridge.subscribe_async("studio_tool", "mesh.*", on_event) if not bridge.wait_until_connected(): bridge.close() raise RuntimeError("Subscription handshake failed") # Keep bridge alive while your tool is running, and call bridge.close() # when your tool shuts down.` An empty filter matches every event type. A filter that ends in `.*`, such as `mesh.*`, matches every event type with that prefix. Any other filter must match the event type exactly. Desktop doesn’t send an app its own events, and it delivers an event that has a `target_app` only to that app. Your callback runs on a background thread. Move scene changes to the DCC’s main thread, and Qt UI changes to the Qt main thread through a queued call. When your stream connects, `BridgeClient` first calls your handler with an empty `task.context` event, if your filter matches it. Desktop then sends the latest `task.context`, if it has one. The same empty event arrives if the stream drops, reconnects or overflows. Each time, discard the task context you cached, and wait for a new one before you do work that depends on the task. ## Event fields | Field | Meaning | |---|---| | `event_id` | Identifies the event. Desktop uses it to drop duplicates, and to match an import result to a publish. | | `event_type` | What happened. See Event types. | | `source_app` / `target_app` | The app that sent the event, and an optional single recipient. If `target_app` is empty, every subscriber can receive the event. Otherwise it must be an app ID of 1 to 64 letters, digits, `_` or `-`. Desktop accepts any other value in a `publish` request, but never delivers the event. If `source_app` is empty, Desktop sets it to `rpyc`. | | `file_path` | The file the event is about, if there is one. | | `metadata` | The event-specific fields, as a dictionary. On the wire this is a JSON string named `metadata_json`. | | `task_id` / `changelist_id` | The task and changelist the event belongs to, as top-level fields or as keys in `metadata`. The `publish` request accepts only `metadata_json`, so publishers put them in `metadata`. | | `timestamp` | The time of the event, in Unix seconds. | ## Event types The relay accepts any `event_type`. The events below are the ones that DousenDesktop, the DCC addons and the Unreal plugin send and act on. Validation rule IDs such as `mesh.poly_count` look similar, but they belong to asset validation and are never bridge events. ### Export events from DCCs A DCC addon sends one of these events for each instance you publish, and the Unreal plugin reads it to import the asset. The Desktop install defines these fields in `python/dousen/addons/_ue_contract.py`. | Event | Required metadata | Optional metadata | What it publishes | |---|---|---|---| | `mesh.export` | `suggested_name`, `source_file` | `suggested_ue_path`, `convention_tags`, `cv_tags`, `references`, `material_assignment` | A static or skeletal mesh FBX. A skeletal mesh also produces its skeleton. | | `texture.export` | `suggested_name` (the target mesh), `textures` (a list of absolute paths) | `suggested_ue_path`, `master_material`, `material_assignment`, `import_mode`, `mesh_slot` | A set of textures. | | `animation.export` | `suggested_name`, `source_file` | `suggested_ue_path`, `skeleton`, `convention_tags`, `cv_tags`, `references` | An animation clip FBX. | `anim.export` is an older name for `animation.export`. Desktop and the plugin still accept it, but new tools should use `animation.export`. The metadata fields work as follows: | Field | How it is used | |---|---| | `source_file` and the event’s `file_path` | Set the event’s `file_path` to the exported file. Unreal reads `source_file` from the metadata, or `file_path` if `source_file` is missing. | | `suggested_name` | If it is missing, Unreal uses the base name of the exported file. | | `convention_tags`, `cv_tags` | Objects with string values. Unreal reads the asset type from `convention_tags.asset_type` and stamps the tags on the imported asset as metadata. Convention tags are stored as `Dousen.Convention.`, and CV tags as `dousen_`, for example `dousen_cv_poly_tier`. The `cv_tags` are searchable in the Content Browser. Desktop adds `cv_tags` to a mesh or animation export itself when the metadata has `geometry_stats`. See Auto-tagging on export. | | `references` | The files the scene references. Desktop reports them to DousenCore as asset dependencies. For an animation, Unreal also uses them to find the skeleton. | | `skeleton` | For `animation.export`. If it isn’t set, Unreal follows `references` from the rig scene to the skeletal mesh imported from it, and from there to its skeleton. If that finds nothing, Unreal uses the `*_Skeleton` asset in the destination folder. | | `import_mode`, `mesh_slot` | For `texture.export`. With `mesh_materials`, the default, Unreal binds the textures into the material slots of the target mesh, and `mesh_slot` names the slot to bind. With `textures`, Unreal imports them as standalone texture assets. | | `jira_key`, `source_scene_path`, `source_depot_path`, `source_repo_role`, `sync_manifest` | Optional. Where the source files live in version control. Desktop uses them to register the source asset with DousenCore, which needs an active project. See Source repositories. | | `published_depot_path`, `published_repo_role` | Optional. Desktop also uses them to register the source asset. Unreal stamps them on the imported asset for the Reimport (sync source) menu item. | ### The material_assignment object `material_assignment` assigns catalog materials to mesh slots. It is an alternative to the flat `textures` and `master_material` fields, and Unreal checks it first. Each entry in `assignments` describes one material slot: JSON`"material_assignment": { "catalog_version": 1, "assignments": [ { "mesh_slot": "CrateBody", "material_id": "coated_metal", "material_path": "/Game/Materials/M_CoatedMetal", "textures": {"BaseColor": "C:/Work/Textures/T_Crate_BaseColor.tga"}, "scalar_params": {"RoughnessMult": 0.6}, "vector_params": {"Tint": [1, 0.9, 0.9, 1]} } ] }` | Field | Rules | |---|---| | `mesh_slot` | The material slot or texture set name. Use an empty string for an asset with one slot. | | `material_id`, `material_path` | Each assignment needs one of them. Unreal skips an assignment that has neither. Unreal looks up `material_id` in the project’s material catalog first. If that finds no entry, it loads `material_path`. If that fails too, it uses the default master material. | | `vector_params` | Each vector needs at least three numbers. If you leave out the fourth, Unreal sets the alpha to 1. | | `allow_nanite` | Unreal never reads it from the event. The Nanite setting comes from Allow Nanite on the project’s catalog entry. | The catalog is created in Unreal. See Materials and textures. ### Tracked and untracked exports An export event (`mesh.export`, `texture.export` or `animation.export`) is a tracked publish when its metadata contains both `event_id` and `instance_id`. A tracked publish appears in Publish history and can be retried. It is marked Imported and saved in Unreal only after Desktop receives a matching import receipt from Unreal. Desktop sends a tracked publish to Unreal itself, either to an open editor or through a headless import, so other subscribers never receive it. An export event without those two keys is untracked. Desktop sends it to subscribers and registers the source asset, but it creates no history entry, so Desktop can’t offer a retry and never reports whether an import worked. Desktop doesn’t import an untracked event in the background. An open Unreal editor that receives it reimports an existing asset, or offers an Import prompt for a new one. To make a tracked publish, send these metadata fields: | Metadata field | Requirement | |---|---| | `event_id` | A UUID, or 32 to 128 hexadecimal characters. Use a new value for each publish attempt. Desktop rejects a repeated `event_id` unless the event is identical to the first one. With `BridgeClient.publish()`, pass it as the `event_id` argument or put it in `metadata`. | | `instance_id` | The ID of the instance you are publishing, up to 256 characters. Desktop shows it in the history entry. | | `bundle_id` | Optional, up to 128 characters. Use the same value for instances you publish together. | | `publish_identity` | An object with `credential_id`, `server_url`, `account_id` and `tenant_id` that matches the user signed in to Desktop. Desktop rejects the publish if it is missing or different. The DCC addons read these values from the credential file that Desktop passes to the processes it launches, through `DOUSEN_CREDENTIAL_FILE`, `DOUSEN_CREDENTIAL_ID` and `DOUSEN_CORE_URL`. | | `publish_history` | Optional. `{"validated": true}` records that validation ran before the publish. | Set `file_path` to the exported file, and leave `target_app` empty. Desktop records the file’s size and modification time, and doesn’t offer a retry if the file changes. The whole `metadata_json` value must be 16 KiB or smaller. Desktop keeps only the metadata fields below in the history entry and in the event it sends to Unreal, and drops any others. Maps hold at most 128 entries, and lists at most 256. | Group | Fields kept | |---|---| | Publish tracking | `event_id`, `parent_event_id`, `bundle_id`, `instance_id`, `publish_history`, `publish_identity` | | Unreal import | `suggested_name`, `suggested_ue_path`, `source_file`, `skeleton`, `asset_type`, `format`, `references` | | Materials and textures | `master_material`, `import_mode`, `mesh_slot`, `textures`, `material_assignment` | | Tags | `convention_tags`, `cv_tags` | | Source files | `jira_key`, `source_scene_path`, `source_depot_path`, `published_depot_path`, `source_repo_role`, `published_repo_role`, `sync_manifest`, `storage_type`, `storage_ref` | The event has no field for the target project. Desktop sends a tracked publish to the Unreal project configured in Desktop, and records the publish as unconfirmed if none is configured. Before it sends the import, Desktop checks that the connected editor has that project open. If your tool can’t export an instance, send a `publish.failed` event instead of an export event. Use the `event_id`, `instance_id`, `bundle_id` and `publish_identity` that the export would have used, and leave `file_path` empty. With `BridgeClient.publish()`, pass the `event_id` as the argument and the other three in `metadata`. Desktop lists the instance as failed in Publish history. ### Events from Unreal When you save an asset in the editor, the Unreal plugin publishes an event with `source_app` set to `unreal`. These events reuse the names of DCC export events, but their metadata is different. | Event | Sent when you save | |---|---| | `mesh.export` | A static mesh or skeletal mesh. | | `texture.export` | A `Texture2D`. | | `material.export` | A material or material instance. | All three events carry the same metadata: | Metadata field | Meaning | |---|---| | `asset_path` | The package path in Unreal. | | `asset_class` | The asset class, for example `StaticMesh`. | | `package_file` | The path of the `.uasset` file. | They have no `suggested_name`, `source_file` or `event_id`, so they are never tracked. If you handle `mesh.export` or `texture.export`, check whether `source_app` is `unreal` to tell the two kinds apart. ### dcc.open `dcc.open` asks an app to open a file. Desktop and Unreal handle it in two forms. | Sent by | Metadata | What happens | |---|---|---| | The Open in DCC menu in the Unreal Content Browser. It leaves `target_app` empty. | `jira_key`, `asset_name`, `preferred_dcc` | Desktop handles every `dcc.open` event, whatever its `target_app`. It fetches the asset’s source record from DousenCore, finds the file on the local disk, and launches the app whose ID is `preferred_dcc`. If `preferred_dcc` is empty, it launches the DCC recorded when the asset was published. Desktop ignores the event if `jira_key` or `asset_name` is empty. | | Any client, with `target_app` set to `unreal` or left empty | `asset_path` | Unreal looks up the asset in the Asset Registry and shows it in the Content Browser. If `asset_path` is missing, the plugin uses `file_path`. No built-in addon sends this form. | Houdini, Substance Painter and Substance Designer also subscribe to `dcc.open`. A running session opens the event’s `file_path`, or `metadata.file_path` if you set it. Blender, Maya and 3ds Max don’t handle `dcc.open`. Desktop launches only the apps in its own app list (Settings → DCC Apps). A tool that only calls `register` still appears in the `dccs` response, in Connected apps and in Unreal’s Open in DCC menu, but choosing it in that menu does nothing. To make the tool a launch target, add it to the app list. See Launching DCCs. ### task.context Each time you select a different task in My tasks, Desktop publishes `task.context` with `source_app` set to `dousen_desktop`. Other apps use it to tag their output with the active task without asking Jira. `task_id` and `changelist_id` are both top-level event fields and metadata keys. The metadata has these fields: | Field | Meaning | |---|---| | `task_id` | The ID of the selected task. | | `task_title` | The task’s title. | | `jira_key` | The task’s Jira key, for example `DOU-123`. | | `changelist_id` | The DousenCore ID of the task’s changelist. | | `vcs_changelist_id` | The Perforce changelist number. | | `vcs_changelists` | An object with a `ue` entry and a `source` entry. Each has a `changelist_id` and a `vcs_changelist_id`. In a project without a separate source repository, both entries have the same values. | | `project_id` | The ID of the project that is active in Desktop. | When you sign out, Desktop publishes an empty context. The DCC addons keep the latest context they receive instead of relying on environment variables set when the DCC started. ### import.result After a tracked publish is imported, Desktop gets an import receipt from Unreal. For an open editor, the receipt is the reply to the import that Desktop sends. For a background import, Desktop reads it from the headless import. Desktop uses the receipt to update the history entry. It accepts the same receipt as an `import.result` event, and doesn’t forward that event to subscribers. Your tool doesn’t need to send it. | Metadata field | Meaning | |---|---| | `event_id`, `bundle_id`, `instance_id` | Copied from the publish. Desktop rejects the event if `event_id` is missing or no history entry matches. | | `dispatch_generation` | A number that Desktop adds to each delivery and each retry. Desktop rejects the event if it is missing or doesn’t match the latest delivery. | | `ok`, `saved`, `asset` | The publish becomes Imported and saved in Unreal only if `ok` and `saved` are true and `asset` holds the path of the imported asset. | | `may_have_imported`, `retry_safe`, `error` | If the import isn’t confirmed and `may_have_imported` is true, Desktop records the publish as unconfirmed. A missing `may_have_imported` counts as true. Otherwise it records a failure, and `retry_safe` says whether a retry is allowed. | ## Request operations Send a request with `BridgeClient.request(operation, payload)`. The bridge accepts the operations in the table below. For registration and publishing, use the client methods. The `events` operation returns a short diagnostic history. Live events arrive on the stream. ### Request payload reference | Operation | Payload fields | Response | |---|---|---| | `register` | `id`, and optionally `name`, `command_port` and `capabilities`. | `{"ok": true}`. Status 400 unless the ID is 1 to 64 letters, digits, underscores or hyphens, the name is up to 256 characters, and the command port is from 0 to 65535. Status 429 when 64 apps are already registered. An expired registration still counts toward the 64 until Desktop next answers `dccs`. `exclusive_publish_dispatch` is the only capability Desktop reads, and only the Unreal plugin sends it. | | `unregister` | `id`. | `{"ok": true}`, whether or not the app was registered. | | `dccs` | An empty object. | A JSON array of `{id, name}` objects for the apps in Desktop’s app list and the apps registered over the bridge. A registered app has a `command_port` if it sent one that isn’t 0. | | `status` | An empty object. | `{"apps": [{"app_id", "subscription_count"}]}`, a diagnostic list of the apps that published an event in the last 30 seconds, including apps that publish over the bridge and `dousen_desktop`. An app stays listed for 30 seconds after its last publish. To find the registered apps, use `dccs` or `list_apps()`. `subscription_count` is always 0. | | `publish` | `event_type`, and optionally `source_app`, `target_app`, `file_path` and `metadata_json`. All of them must be strings. | `{"ok": true}`, or status 409 with `{"ok": false, "error_code": "publish_rejected"}`. There are no `task_id` or `changelist_id` fields, so put them in `metadata_json`. | | `events` | Optional `since`, in Unix seconds. | `{"events": [...], "timestamp": ...}` with up to the last 200 events newer than `since`, except events that Desktop dispatches itself. | | `history` | Optional `limit`. The default is 20, and values outside 1 to 50 are clamped to that range. | `{"version": 1, "entries": [...], "capabilities": {"headless_auto_import": ...}}`. The entries are the publishes of the user signed in to Desktop. Each has `event_id`, `bundle_id`, `instance_id`, `event_type`, `state`, `error_code`, `hint`, `validated_at`, `exported_at`, `delivered_at`, `imported_at`, `dispatch_generation` and `retry_allowed`. The state is `validated`, `exported`, `delivered`, `imported`, `failed` or `unconfirmed`. | | `retry` | `event_id` of the original publish, in the same format as for a publish. | Status 202 with `{"ok": true, "error_code": "started", "dispatch_generation": ...}` when the retry starts. Otherwise status 404 (`not_found`), 409 or 503 (`persistence_failed`), with `error_code` saying why. For 409 it is one of `session_invalid`, `already_imported`, `reconciliation_required`, `not_retryable`, `already_in_flight`, `source_missing`, `source_changed` and `target_project_mismatch`. | | `source/ensure-mapped` | `path`, a depot path or a local path. | Maps the folder for the path’s repository in the Perforce workspace, so you can add a new file there. Returns `ok`, `role`, `depot_path` and, if known, `local_path`. | | `source/sync` | `depot_path`, and optionally `role`. Without `role`, Desktop works it out from the path. | Syncs the file and its `.dousen_meta.json` sidecar, if the depot has one. Returns `ok`, `local_path` and `synced`. Fails if the local file has unsubmitted edits. | Besides the statuses in the table above, the bridge returns these: | Status | Meaning | |---|---| | 400 | Malformed JSON or an invalid field. | | 404 | Unknown operation. | | 503 | Desktop can’t handle the request yet, or didn’t answer within 15 seconds. | Once Desktop accepts a `source/*` request, it reports a Perforce or routing failure as status 200 with `"ok": false` and an `error` message. A missing `path` or `depot_path` returns 400. A request that takes longer than 15 seconds returns 503, but the sync may still finish. Use these operations with the source-repository workflow. ### Read an error response `BridgeClient.request` returns the response body for any 2xx status. A successful `retry` returns status 202, so you can read `error_code` and `dispatch_generation` from the return value. For any other status it raises `dousen.bridge.BridgeError`, a subclass of `OSError`. Its `status` and `body` attributes hold the status and the response body, so an existing `except OSError` handler still catches it. PYTHON`from dousen.bridge import BridgeClient, BridgeError with BridgeClient() as bridge: try: reply = bridge.request("retry", {"event_id": event_id}) print(reply.get("error_code")) except BridgeError as error: print(error.status, error.body)` ## Limits and failure handling - A request or response value can be up to 4 MiB of JSON. `BridgeClient` raises `ValueError` for a larger request before it sends it. The bridge allows only the operations on this page and the event stream. It doesn’t allow pickle, remote attribute access or remote execution. - At most 64 apps can be registered, and registrations expire after 90 seconds. - Each subscriber has a mailbox limited by the number of events and their total size. If it overflows, the subscriber receives a gap marker, which `BridgeClient` turns into an empty `task.context`. - Each stream has a session ID and a sequence number. `BridgeClient` uses them to skip events it already received. - A request is sent once. If the response is lost, the result is unknown, and the client doesn’t send the request again. A `True` result from `publish` means that Desktop accepted the event. It doesn’t mean that Unreal imported the asset. After a timeout or a `False` result, Desktop may still have accepted the event, so don’t publish again automatically. Check Publish history and the destination in Unreal first. See Recover from a failed publish. If Desktop restarts, it generates a new bridge token and closes the stream. Your subscription reconnects with the new token. Discard any task context you cached. ## Source files The Desktop install includes the Python client, `python/dousen/bridge.py`, and its RPyC transport, `python/dousen/rpc.py`. To start a tool with a DCC, see Loading studio tools. Previous ← Tools and plugins Next Troubleshooting → ## Naming conventions — Dousen URL: https://dousen.io/docs/conventions.html Summary: Define asset naming conventions once, in YAML, per project — enforced in Blender, Maya, and every other DCC before export. Updated October 2026 Describes how to write a project’s naming conventions, which set how each asset is named and where it is stored, in Unreal and on disk. You write one document per project. ## Configure and test your first naming rule You need an Admin account, a project, and a small saved source asset for testing. Start with one asset type and one branch of the taxonomy, then add the rest. - In the portal, open Projects, select your project, and open the Conventions tab. Copy the current document somewhere safe so you can restore it later. - Edit the document, or choose a starting point in Preset and click Load. The example below is another starting point. Set the asset type, its prefix, the categories, and any dimensions your artists need. - Click Save. If the portal shows an error, fix it. Then reopen the editor and check the saved document. - Launch a test DCC for this project from DousenDesktop. Set the collected instance’s type, taxonomy, and dimension tags, which must match the names in the document, and check the name and destination that Dousen suggests. - Validate a correctly named test asset and one that is named wrong on purpose. Check that each gives the result you expect at the configured severity. - Publish the correct asset and check its name and folder in Unreal. Clients cache conventions for 5 minutes, so wait that long or restart them before you test a change. Changing a naming rule doesn’t rename Unreal assets that already exist. Reimport keeps the conventions stored with each asset unless you set `bRefreshConventionsOnReimport=true` in the plugin settings. Before you change a live project, read Reimport behavior. ## How conventions are compiled and used - You write the document in the web portal, as YAML (the default) or as a Lua script when you need computed rules. See Authoring in Lua. - DousenCore compiles it. It resolves the taxonomy tree, adds the full set of validators to every node, and reports errors such as an invalid regex or a malformed structure. - Clients fetch the compiled form from `GET /api/projects/:id/conventions/compiled` and cache it for 5 minutes, so a change can take that long to reach an open DCC. ## A complete example The current schema is version 3. YAML`version: 3 dimensions: variant: required: false values: [Base, Hero, Damaged] lod: required: false values: [LOD0, LOD1, LOD2] number: required: false values: [] # empty = free-form validators: # global — apply to every asset - id: naming.convention severity: error - id: naming.no_special_chars severity: error asset_types: static_mesh: prefix: SM suffix: "" naming: pattern: "^SM_[A-Za-z0-9_]+$" # guard rail the final name must satisfy max_length: 64 source_path: mirrors_engine: true validators: # scoped to this asset type - id: mesh.poly_count severity: warning params: { max_tris: 50000 } categories: Props: folder: true subcategories: Weapons: folder: true prefix: Wep validators: # scoped to this node + everything below - id: mesh.poly_count severity: error # tightens the asset-type rule params: { max_tris: 20000 } subcategories: Melee: folder: true` With this document, a Static Mesh named Sword at `Props/Weapons/Melee` with the variant Hero gets the name `SM_Wep_Sword_Hero` and the engine folder `Props/Weapons/Melee`. Asset type keys must be the snake_case ids that the clients use, such as `static_mesh`, `skeletal_mesh`, `texture`, `animation_sequence`, `hda`, and `vat`. If you use a different key, such as `StaticMesh`, no instance matches it, so its prefix isn’t enforced and the portal’s rule picker hides the mesh rules under it. ## The taxonomy tree The first level under an asset type is `categories`. Each node in it can nest `subcategories`, and every node has the same fields at every depth. There’s no maximum depth, and a leaf node can be just `{}`. ``` static_mesh asset_type — prefix "SM" └─ Props folder ✓ prefix "" suffix "" └─ Weapons folder ✓ prefix "Wep" └─ Melee folder ✓ prefix "" └─ Daggers folder ✓ prefix "Dgr" └─ (leaf — no subcategories) ``` A client finds an asset’s place in the tree with an ordered list of node names, the taxonomy path, for example `["Props", "Weapons", "Melee", "Daggers"]`. For that path, a Static Mesh named Sword resolves to: - Name: `SM_Wep_Dgr_Sword`: the asset type’s `SM`, then `Wep` from Weapons and `Dgr` from Daggers. Props and Melee have no prefix. - Engine folder: `Props/Weapons/Melee/Daggers`, because every node on the path has `folder: true` (the default). A node’s folder and its name tokens are independent. A node with a `prefix` or `suffix` and `folder: false` adds a token to the name without creating a subfolder, so every weapon can get a `Wep` token without a `Weapons/` folder. A node with neither, like `Props` and `Melee` above, only adds a folder segment. ## Keyword reference ### Top level | Key | Type | Required | Notes | |---|---|---|---| | `version` | int | yes | Must be `3`. A missing or different value is a compile error. | | `dimensions` | map | no | Extra naming parts that are appended to names, such as a variant or a LOD. Default `{}`. | | `validators` | list | no | Rules that apply to every asset. Default `[]`. | | `asset_types` | map | no | One entry per asset type. Default `{}`. | | `interchange` | map | no | Unreal Interchange import profiles. DousenCore validates it when you save and passes it through the compiled document. See Set up an import profile. | ### dimensions. | Key | Type | Default | Notes | |---|---|---|---| | `required` | bool | `false` | Advisory. Client UIs show it, but name resolution doesn’t enforce it. | | `values` | list of strings | `[]` | The pick-list shown in the DCC Set Up Asset panels. Empty means free-form. Name resolution doesn’t check that a value is in the list. For a dimension that isn’t `required`, the pick-list starts at (none), and the tag stays unset until the artist chooses a value. | You can declare any dimension key, but only `variant`, `lod`, and `number` are added to names, in that order. Other dimensions appear only in client UIs and in the convention tags. `variant` is left out of the name when its value is exactly `Base`. The `import_profile` dimension selects an Interchange profile. Each of its `values` must name a profile in the `interchange` block, and the dimension can’t be `required`. DousenCore checks both when you save. Artists can also choose a profile for one instance with Set Import Profile in the Publish tab. See Set up an import profile. ### Validator entries The same entry format works at all three levels: global, asset type, and taxonomy node. An entry applies at the level where you place it and to everything below it. For what each rule does and how levels override each other, see Asset validation. | Key | Type | Default | Notes | |---|---|---|---| | `id` | string | required | The rule id, for example `mesh.poly_count`. The portal accepts an id that no DCC implements. A DCC with no plugin for it reports a warning that the rule was skipped. | | `severity` | string | — | `error` blocks the export and `warning` is advisory. If you leave it out, the DCC addons treat the rule as `error`. | | `enabled` | bool | `true` | Set `false` to turn the rule off at this level and below. | | `params` | map | `{}` | Rule-specific parameters. When a deeper level restates a rule, its params are merged key by key over the shallower ones, so a node can change only `max_tris`. | | `name` / `category` | string | — | Optional display metadata. The portal fills these in from the catalog. | ### asset_types. | Key | Type | Default | Notes | |---|---|---|---| | `prefix` | string | `""` | The first token of every name of this type (for example `SM`). | | `suffix` | string | `""` | The last token of every name of this type. | | `naming.pattern` | regex | — | A guard rail that the final assembled name must match. It doesn’t build the name. An invalid regex is a compile error that names the asset type. | | `naming.max_length` | int | — | The maximum length of the final name. | | `source_path.template_override` | template | — | Where the working file lives when it doesn’t mirror the engine path. See Source paths. | | `source_path.mirrors_engine` | bool | `true` | `true` unless the asset type has a `template_override`. DousenCore derives this value and ignores what you write. | | `validators` | list | `[]` | Rules for this asset type, merged over the global rules. | | `categories` | map | `{}` | The first level of the taxonomy tree. | The first level under an asset type must be `categories`. Putting `subcategories` directly under an asset type is a compile error. ### Taxonomy nodes (categories and subcategories) | Key | Type | Default | Notes | |---|---|---|---| | `folder` | bool | `true` | When `true`, the node’s name becomes a folder segment in the engine path. Set `false` for a node that only adds to the asset name. | | `prefix` | string | `""` | A name token that comes before the asset name. | | `suffix` | string | `""` | A name token that comes after the asset name. | | `required` | bool | `false` | Advisory flag for client UIs. | | `validators` | list | `[]` | Rules for this node and everything below it. | | `subcategories` | map | `{}` | Child nodes with the same fields, to any depth. | ## How a name is assembled Dousen joins these parts with `_` and skips empty ones, in this order: - the asset type’s `prefix` - each taxonomy node’s `prefix`, along the path from root to leaf - the asset name - each taxonomy node’s `suffix`, also from root to leaf - the `variant` (unless it is `Base`), then `lod`, then `number` - the asset type’s `suffix` The engine folder path is built separately: Dousen joins the names of the nodes whose `folder` is `true` with `/`. Node prefixes and suffixes don’t affect it. When you export, the `naming.convention` validator checks the assembled name against the asset type’s `naming.pattern` and `naming.max_length`. ## Source paths By default (`mirrors_engine`), an asset’s working file has the same relative path as its engine folder. A mesh that goes to `Props/Weapons` keeps its `.blend` or `.ma` file under `Props/Weapons` in the source root. To store sources somewhere else, give the asset type a `template_override`: YAML`source_path: template_override: "Art/Source/{{ category }}/{{ subcategory }}"` Use double-brace placeholders such as `{{ category }}`. Single-brace placeholders such as `{ category }` aren’t substituted. These variables are available: | Variable | Value | |---|---| | `category` | The first taxonomy segment (for example `Props`). | | `subcategory` | The second taxonomy segment (for example `Weapons`). | | `variant`, `lod`, `number`, … | The dimension values selected for the asset (any selection key the DCC sends). | `template_override` is the only place where v3 uses templates. The DCC addons and the Unreal plugin define only `category` and `subcategory` from the taxonomy path, so don’t reference deeper segments. The asset’s name isn’t a template variable. ### Worked examples The DCC addons, the Unreal plugin, and DousenCore all render a `template_override` string to the same result. | `template_override` | Taxonomy path | Selections | Resolved source path | |---|---|---|---| | `Art/Source/{{ category }}/{{ subcategory }}/Textures` | `Props/Weapons` | — | `Art/Source/Props/Weapons/Textures` | | `Rigs/{{ subcategory }}/{{ variant }}` | `Characters/Heroes` | `variant: Hero` | `Rigs/Heroes/Hero` | | `{{ category }}/{{ subcategory }}` | `Props/Weapons/Melee/Daggers` | — | `Props/Weapons` (the third and fourth segments are ignored) | | `{{ category }}/LODs/{{ lod }}` | `Environment` | `lod: LOD1` | `Environment/LODs/LOD1` | If a template uses a variable that the asset doesn’t have, for example `{{ subcategory }}` when the taxonomy path has only one level, the DCC addons fall back to the engine folder path, and the Unreal plugin leaves the placeholder text in the path. Saving doesn’t check `template_override`, so resolve a real asset to test a template. ## Authoring in Lua Write the document as a Lua script when your rules are computed, for example when dozens of asset types share a pattern, prefixes come from a table, or poly budgets follow a formula. In the editor, set Mode to Lua Script, or save through the API with `?type=lua`. The script defines a `config()` function that returns a table with the same version 3 structure as the YAML. DousenCore runs it when you save and when it compiles the document, so clients get the same compiled JSON whichever format you use. LUA`-- Generate several asset types from one table. local types = { { key = "static_mesh", prefix = "SM" }, { key = "skeletal_mesh", prefix = "SK" }, { key = "texture", prefix = "T" }, { key = "animation", prefix = "A" }, } function config() local asset_types = {} for _, t in ipairs(types) do asset_types[t.key] = { prefix = t.prefix, naming = { pattern = "^" .. t.prefix .. "_[A-Za-z0-9_]+$" }, categories = { Characters = {}, Environment = {}, Props = {} }, } end return { version = 3, dimensions = { number = { required = true, values = {} } }, validators = { { id = "naming.convention", severity = "error" }, }, asset_types = asset_types, } end` The script runs in a sandbox inside DousenCore. Besides the base functions such as `ipairs`, only the `table`, `string`, and `math` libraries are available. `os`, `io`, `require`, `load`, `loadfile`, `dofile`, `loadstring`, `dostring`, `package`, `debug`, and `collectgarbage` are removed, and `string.dump` is disabled so that a script can’t produce bytecode. A script can use 1 MiB of memory and 10,000 VM instructions. After that, it stops with the error `"instruction limit exceeded"`. There is no wall-clock timeout. When you save, DousenCore rejects a script that has a compile error, has no `config()`, or returns something that isn’t a valid version 3 table. The editor shows the error. Older Lua conventions defined `resolve()` and `validate()` functions. DousenCore no longer supports that format and rejects a script that defines `resolve()`. There is no automatic migration, so move the logic into a `config()` that returns the version 3 table. ## The portal editor - The Conventions tab has a code editor with Mode set to Template YAML or Lua Script. Preset and Load replace the editor content with one of these starting points: UE5 Allar Style Guide, Minimal, Nanite + Lumen — Static, and Nanite + Lumen — Foliage for YAML, and the Allar and Minimal presets for Lua. Upload File loads a `.yaml`, `.yml`, or `.lua` file. Save checks the document and stores it. - The Validators tab shows the compiled taxonomy as a tree, where you edit each node’s rules. These edits change the YAML document for you. For a project that uses Lua, the tree is read-only. See Enable and test a rule. - In Lua Script mode, a side panel adds Validate Names. Enter asset names, one per line. The panel checks each name against the `naming.pattern` and `naming.max_length` of the asset type named in the `asset_type` field of the Context (JSON) box, and shows which names pass or fail, with the reason. ## How each client resolves conventions The DCC addons and the Unreal plugin read only the compiled JSON from `/conventions/compiled`. They never parse the YAML or Lua. Both follow How a name is assembled, so the same input gives the same name in Blender and in Unreal. ### DCC addons (Blender, Maya, 3ds Max, …) The addons fetch the compiled JSON as the signed-in artist and cache it for 5 minutes. They use it to: - Fill the cascading category and subcategory dropdowns in each addon’s Set Up Asset panel. Each pick narrows the next level’s options, to whatever depth the tree has. - Suggest the name, engine path, and source path, and build a flat `convention_tags` dictionary with the asset type, the `/`-joined taxonomy, and the selected dimension values. Dousen embeds the tags as custom properties or FBX metadata, so Unreal’s importer recovers the asset’s taxonomy without the artist entering it again. - Infer the tags of an asset that was never tagged, when validation finds no saved tags. Dousen matches the longest asset-type prefix on the file name, matches path segments to taxonomy node names (ignoring case), and scans path segments for dimension values. If a fetch fails, see DousenCore is unreachable. ### The Unreal Engine plugin The plugin fetches the compiled JSON when the editor starts and then every 5 minutes. It resolves names from the same flat tags (`asset_type`, `taxonomy` joined by `/`, `variant`, `lod`, and `number`), joins the folder-flagged node names for the engine path, and fills in `template_override` for the source path. When a bridge event arrives without a suggested name, the plugin builds the name and engine path itself. If a fetch fails, see DousenCore is unreachable. ### The web portal The portal is the only client that also writes the document. The Validators tab compiles the stored document on every request, and Validate Names compiles the text in the editor. Neither uses the 5-minute cache. ## What is checked when | Moment | What can fail | |---|---| | Saving YAML | Invalid YAML, and any compile error: a missing or wrong `version`, an invalid `naming.pattern` regex, `subcategories` directly under an asset type, or a malformed validator entry, or an invalid `interchange` block. The error names the field, for example `Convention error: 'interchange.profiles..' must be …`. It also fails if an `import_profile` value names no profile, or if that dimension is `required`. | | Saving Lua | Lua compile errors, a missing `config()`, a return value that isn’t a table, and the same compile errors as for YAML. | | Fetching the compiled document | DousenCore compiles the stored document again. If it no longer compiles, the request returns HTTP 500 with the error as the body. An invalid `interchange` block that was stored earlier is left out instead, and the Conventions page shows a warning. | | Never checked | Validator ids that no DCC implements (the DCC reports a skipped-rule warning), dimension values outside `values` (advisory), and the contents of `template_override`. | ## Who can view and edit Any signed-in user, and any DCC addon or Unreal plugin that authenticates with a token, can fetch the document or the compiled JSON. Only an Admin can save. The portal editor requires the Admin role, and `PUT /api/projects/:id/conventions` also returns `403 Forbidden` for any caller whose role isn’t Admin. ## API reference | Endpoint | Purpose | |---|---| | `GET /api/projects/:id/conventions` | The document as you wrote it, as YAML or Lua source. A project that has never saved a document gets the bundled UE5 Allar-style preset, which is the same document the portal offers as a starting point. | | `PUT /api/projects/:id/conventions` | Replaces the document. Admin only. `?type=lua` validates and stores it as a Lua script. `?type=template`, or no parameter, validates it as YAML. Any other `type` value returns `400`. | | `GET /api/projects/:id/conventions/compiled` | The compiled JSON that clients use, with the taxonomy resolved and `effective_validators` added to every asset type and node. | | `GET /api/projects/:id/conventions/json` | An alias of `/compiled`. | ## Troubleshooting ### A change doesn’t appear in a DCC or in Unreal To fetch conventions before the 5-minute cache expires: - DCC addons: restart the DCC. There is no button to reload conventions, and a new process starts with an empty cache. - Unreal: restart the editor or reload the plugin. ### DousenCore is unreachable If a fetch fails (a network error, a non-2xx response, or malformed JSON), the DCC addons keep using the last copy they loaded. If they never loaded one, they skip convention-based suggestions, and validators use the validator catalog if DousenCore still serves it, and otherwise the default rules built into the addon, instead of the project’s rules. The Unreal plugin logs a `LogDousenUE` warning and marks the conventions as unavailable until the next successful fetch, within 5 minutes of DousenCore coming back. While they are unavailable, the Dousen import pipeline (on by default) refuses to import new assets with the message `Project conventions unavailable; fetch conventions before importing new assets`. Reimporting an existing asset keeps using the conventions stored with that asset. ### A saved change has no effect DousenCore compiles the document when you save it, so the portal and `PUT` reject a document that doesn’t compile. See What is checked when. If `/conventions/compiled` still returns HTTP 500 with a compile error, the DCC addons keep their last good copy and Unreal marks the conventions as unavailable. To see the error, open the document in the portal editor and save it again. Previous ← Unreal Engine Next Asset validation → ## DCC addons — Dousen URL: https://dousen.io/docs/dcc.html Summary: Dousen addons for Blender, Maya, Houdini, 3ds Max, Substance Painter, and Substance Designer — publishing, validation, and task context inside each DCC. Updated October 2026 Describes the Dousen addons for Blender, Maya, 3ds Max, Houdini, Substance Painter, and Substance Designer, and the controls each one adds to its application. Each addon collects the publishable parts of your scene as instances, validates them, and sends the exported files to Unreal through the bridge. For the validation rules, see Asset validation. For the Unreal plugin, see Unreal Engine. ## Open the panel and publish your first instance - In DousenDesktop, select your project and task. Open Settings → DCC Apps and check the path to the application’s executable. - Launch the application from the apps bar and save your scene under the project’s source root. - Open the Dousen panel. Maya and 3ds Max open it at startup, and the Substance applications show it as a dock. In Blender, press N over the 3D Viewport and select the Dousen tab. Houdini has no panel, so use the Dousen shelf. - In the Publish tab, check the instances you want to publish. If you change the scene, click Reset. In Blender, click Refresh Instances. - In Maya, 3ds Max, Substance Painter, and Substance Designer, if an instance’s type is wrong, right-click it and choose a type under Set Type. Point to the instance name to see its Unreal destination. - If your project uses a material catalog, assign materials as described in Materials and textures. - Click Validate (in Blender, Run Validation) and fix any errors. Then click Publish (in Blender, Publish Checked Instances). - Open the Publish history tab in DousenDesktop and wait for Imported and saved in Unreal. ## How the addons load DousenDesktop ships the addons, so you don’t install anything in each application. When you launch an application from the apps bar, Desktop loads its addon and passes the project, task, and sign-in details it needs. See Launching DCCs. - An application you start from a desktop shortcut has no Dousen panel. - After you update DousenDesktop, restart any running applications so they load the new addon code. - If your studio runs its own startup scripts, see Loading studio tools for when they run. ## What each addon can do Maya, 3ds Max, Substance Painter, and Substance Designer share one Qt panel, with the same Publish and Perforce tabs in each. The Qt panel shows tab names in capital letters. Blender uses native panels, and Houdini uses shelf tools. | Capability | Blender | Maya | 3ds Max | Painter | Designer | Houdini | |---|---|---|---|---|---|---| | Where it appears | Sidebar tab | Shelf and dock | Menu or toolbar, and dock | Dock | Dock | Shelf | | How you publish | Publish Checked Instances | Publish tab | Publish tab | Publish tab | Publish tab | Export HDA, VAT, or Alembic shelf tools | | Validation blocks publishing | ✓ | ✓ | ✓ | ✓ | ✓ | — (export tools don’t validate) | | Fix button (only for rules that offer a fix) | Fix | Repair | Repair | Repair | Repair | — (console output only) | | Select Invalid | — | ✓ | ✓ | — | — | — | | Set Import Profile | — | ✓ | ✓ | — | — | — | | + Instance from Selection | — | ✓ | — | — | — | — | | Auto-publish on save | ✓ | ✓ | ✓ | ✓ | — | — (no toggle) | | New asset setup | ✓ | ✓ | ✓ | — | — | — | | Material picker | ✓ | ✓ | ✓ | ✓ | ✓ | One material | | Perforce actions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Send to Painter | ✓ | ✓ | ✓ | — | — | ✓ | | Send to Unreal button | — | — | — | ✓ | ✓ | ✓ | | Task context | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | The built-in rules that offer a fix are the frozen-transform checks in Blender and Maya. 3ds Max, Painter, and Designer have no built-in fixes. In Blender, Maya, and 3ds Max, use Publish to send meshes to Unreal. These addons also have a `send_to_unreal()` Python function for studio scripts. ## Task context When you select a task in DousenDesktop, Desktop sends its Jira key and changelist to every running DCC. The addons tag what you publish with the task and associate the files with its changelist. A DCC that you launch while a task is selected also receives it at startup, in the environment variables listed in Loading studio tools. The header of each Qt panel shows the current task and the Perforce stream, or Classic depot for a project without streams. After you switch tasks, check the header before you publish. ## Auto-tagging on export When Blender, Maya, 3ds Max, or Houdini exports a mesh or animation, the addon measures the geometry and sends the numbers with the export. DousenDesktop turns them into these tags before it delivers the event, so Unreal receives them with the first import. Textures get no tags. | Tag | Values | |---|---| | `cv_poly_tier` | `low` for fewer than 5,000 triangles, `mid` for fewer than 50,000, `high` for 50,000 or more | | `cv_has_uvs` | `true` if the mesh has UVs | | `cv_is_skinned` | `true` if the mesh is skinned: it has a skin cluster in Maya, a Skin modifier in 3ds Max, an Armature modifier in Blender, or a `boneCapture` attribute in Houdini | Desktop also saves the tags on the asset’s source record in DousenCore, and Unreal stores them as `dousen_cv_*` metadata that you can search in the Content Browser. There is no review step and no setting to change. ## What becomes an instance? | Application | What Dousen collects | How to create your own instance | |---|---|---| | Blender | Each top-level Collection that contains a mesh. Objects that sit directly in the Scene Collection aren’t collected. | Add a custom property named `dousen_instance` to a Collection at any depth. If its value is text, that text becomes the instance name. | | Maya | Each top-level group or mesh transform that contains a mesh, and each DousenClips clip if DousenClips is installed. | Select objects and click + Instance from Selection, or add a `dousenInstance` attribute to an object set. | | 3ds Max | Each top-level node whose hierarchy contains a mesh. | Create a named selection set. Every named selection set becomes an instance. | | Substance Painter | Each texture set in the open project. | Not needed. | | Substance Designer | Each compositing graph in the loaded packages. | Not needed. | | Houdini | Each `geo` node directly under `/obj`, unless a node inside it has the `dousen_instance` user data. | Add `dousen_instance` user data to a node. If its value is text, that text becomes the instance name. | Instances you create yourself take priority, and their objects aren’t published a second time by the automatic rule. In 3ds Max, a selection set that holds only part of a node tree takes just those nodes out of the automatic instance, which keeps the rest. In Maya, an export set that holds only part of a group takes the whole group out of automatic publishing, and the Publish tab shows a note such as |grp skipped: … Put the remaining children in their own export set. Do that, or the remaining children aren’t published. If nothing is collected, nothing is published, so organize your geometry into one of the structures above or create your own instance. ## The Publish tab The Qt panels share this tab. When you open it, Dousen collects the instances in your scene. Only checked instances are validated and published, and the checked state is saved in the scene. For the whole workflow, see Publishing assets. Screenshots on this page use a sample project. | Control | What it does | |---|---| | Reset | Collects the instances again. Use it after you change the scene. | | Validate | Validates the checked instances without exporting anything and lists the results. | | Publish | Validates the checked instances, then exports and publishes them. Errors stop the publish. If only warnings remain, Dousen asks N warning(s) found. Publish anyway?, and No is the default. | | Group by Type | Arranges the list by instance type. It doesn’t change which instances are checked. | | Right-click → Set Import Profile | Sets the instance’s `import_profile` from the profiles the project defines, or (none) to clear it. The choice overrides the scene’s tag. Maya and 3ds Max only; texture instances never take a profile. See Interchange. | | Right-click → Set Type | Changes an instance’s asset type. Dousen resolves the name and destination again and clears the instance’s validation results. | | + Instance from Selection | Maya only. Groups the selected objects into one explicit instance. | | Repair | Appears on a failed rule when the validator provides a fix. Dousen applies the fix and runs that rule again. | | Select Invalid | Selects the failing objects in Maya and 3ds Max. Painter and Designer have no scene selection to drive, so the button doesn’t appear there. | | Checkbox next to a rule | Clear it to skip the rule. A skipped rule doesn’t block Publish. | In the results, failing and warning rules come first, and passing rules collapse into one row. The log below the results records each step. If two checked instances would export to the same file, Publish is unavailable until you rename or retag one of them. In the New Asset controls of Blender, Maya, and 3ds Max, each optional convention dimension starts at (none), so the tag stays unset until you choose a value. Dimensions your conventions mark as required still need one. ## Blender Press N in the 3D Viewport to open the sidebar, and select the Dousen tab. The Validation, New Asset, Materials, and File Status (P4) sub-panels start collapsed. | Panel | Control | What it does | |---|---|---| | Dousen | Auto-publish on Save | Publishes the checked instances each time you save. See Auto-publish on save. | | Dousen | Refresh Instances | Lists the Collections that Dousen collects, each with a checkbox. The checkbox is saved on the Collection. | | Dousen | Publish Checked Instances | Opens a dialog that says Checked instances are revalidated before export. Dousen validates the checked instances and publishes them. Errors stop the publish. Warnings also stop it unless you select Publish despite validation warnings. | | Dousen | Send to Substance Painter | Appears when Substance Painter is connected. Exports the selected objects as an FBX file next to the `.blend` file and sends it to Painter. | | Validation | Run Validation | Validates the checked instances and lists the results by category. A failed rule shows Fix when the validator provides one. A second Publish Checked Instances button here is enabled after a validation with no errors. | | New Asset | Set Up Asset | Saves the `.blend` file to the source path that your conventions resolve, then adds it to the task’s changelist in Perforce. Choose a name, a type, and the taxonomy first. For an animation asset, you can pick a rig to link into the scene. | | Materials | Refresh Material Catalog, Auto-Fill Textures | Assign a catalog material to each material slot of the active object. Select the edit icon beside a slot (Edit Material Slot) to bind its textures and parameters. Auto-Fill Textures guesses texture bindings from file names. | | File Status (P4) | Check Out Source, Sync & Reload (not at latest), Revert Checkout, Refresh | Shows the lock state of the current `.blend` file. Only the button that applies to the file’s state appears. | Each instance is exported with the objects in its Collection, including an armature, so a skeletal mesh brings its rig but no other instances. Before the export, Dousen writes the convention tags to those objects as custom properties. An animation instance exports its own objects and rig to FBX, like a mesh instance. ## Maya Maya starts with a Dousen shelf and a docked panel. The panel has the tabs Publish, Perforce, New Asset, Materials, and Tools. | Where | Control | What it does | |---|---|---| | Shelf | Dousen | Opens the panel. | | Shelf | Dousen Validate | Opens the panel on the Publish tab. | | Shelf | Dousen Asset | Opens a window that does the same as the New Asset tab. | | Shelf | Send to Painter | Appears only if Substance Painter was connected when Maya started. Exports the selection as an FBX file and sends it to Painter. | | Panel | Publish tab | Collects, validates, and publishes instances. See The Publish tab. | | Panel | New Asset tab | Load Conventions, then choose a name, type, and taxonomy and click Set Up Asset. Dousen saves the `.ma` file to the resolved source path and adds it to the task’s changelist. | | Panel | Materials tab | The catalog material picker. See Materials and textures. | | Panel | Tools tab | Send to Painter is enabled while Painter is connected. The Auto-Publish group has the Publish mesh.export on save checkbox. | To group loose meshes, or a rig’s meshes and skeleton, into one instance, select them, click + Instance from Selection in the Publish tab, and enter a name. Maya creates an object set with a `dousenInstance` attribute. If the set holds only part of a top-level group, put the group’s other children in their own set. Each instance exports as its own FBX file with the project’s `export_presets.maya` settings, and a skinned mesh includes its skeleton. An animation instance exports its own objects and skeleton roots to FBX, except a DousenClips clip, which exports through DousenClips. Before the export, Dousen writes convention tags as string attributes on the mesh transforms. ## 3ds Max The 3ds Max addon requires 3ds Max 2025 or later (PySide6). 3ds Max opens the same docked panel as Maya at startup, with the same tabs, and a Dousen menu appears before the Help menu. | Menu item | What it does | |---|---| | Dousen Panel | Shows or hides the docked panel. | | Publish | Opens the panel on the Publish tab. | | New Asset | Opens a dialog that does the same as the New Asset tab. | | Send to Substance Painter | Appears only if Substance Painter was connected when 3ds Max started. Exports the selected objects as an FBX file and sends it to Painter. | As in Maya, the panel’s Tools tab has Send to Painter and the Publish mesh.export on save checkbox. To export an instance, 3ds Max selects its nodes, plus the skeleton root bones for a skinned mesh, and exports the selection as FBX. An animation instance exports its own nodes and skeleton roots to FBX. Dousen writes convention tags into each exported node’s user-defined properties as lines in the form `dousen_=`. ## Substance Painter Painter shows a docked panel with the tabs Publish, Perforce, Export, and Tools. Textures need a target Unreal mesh. If Dousen exported the mesh, it reads the target from the mesh’s metadata sidecar. Otherwise, on the Export tab, enter the mesh path in Target Unreal mesh, for example `/Game/Props/S_Crate.S_Crate`, and click Use target mesh. Without a target, validation reports an error named Target Unreal mesh. | Tab | Control | What it does | |---|---|---| | Publish | Publish | Exports each checked texture set to the `Textures` folder under the source root and publishes one `texture.export` event per set. The default format is TGA, or the `format` set in `export_presets.substance_painter`. Dousen refuses a format that isn’t in `texture.allowed_formats` and shows the reason in the Publish results. | | Export | Export Textures | Exports every texture set to the same folder without publishing them. | | Export | Send to Unreal | Runs the same validation and publish as the Publish tab. | | Export | Load Materials, Texture Set Materials, Material Details | The catalog material picker, with one material per texture set. See Materials and textures. | | Tools | Publish textures on save | See Auto-publish on save. | If you export with Painter’s own export dialog, Dousen publishes each exported file as a `texture.export` event. It prints a warning if a file’s format isn’t in the project’s `texture.allowed_formats` setting. When another application sends a mesh to Painter, for example with Send to Painter, Painter replaces the mesh of the open project. If no project is open, it creates a project from the mesh. ## Substance Designer Designer shows a docked panel with the tabs Publish, Perforce, Export, Materials, and Tools. | Tab | Control | What it does | |---|---|---| | Publish | Publish | Bakes the graphs in each package once, then publishes one `texture.export` event for each checked graph, with the assignment from the Materials tab. Dousen can’t bake a single graph on its own, so every graph in the package is baked. | | Export | Export Baked Textures | Renders the graphs and exports the textures from their output nodes to the `Textures` folder under the source root. The default format is TGA, or the `format` set in `export_presets.substance_designer`. A format that isn’t in `texture.allowed_formats` is refused, and the Export tab shows why. | | Export | Export .sbsar | Exports the package as a `.sbsar` file to the `Materials` folder under the source root. | | Export | Send to Unreal | Runs the validated Publish flow for the checked graphs and switches to the Publish tab, where the progress appears. The default format is TGA unless `export_presets.substance_designer` sets another. | | Export | Send .sbsar to Unreal | Exports and publishes the `.sbsar` file. It doesn’t run if validation reports errors. | | Materials | Catalog material picker | One material per graph. See Materials and textures. | When another application sends a mesh to Designer, Designer stores the file path for you to use in your baking graph. It doesn’t connect the mesh to a node. ## Houdini The Dousen shelf holds these tools. Dousen: Send to Painter appears only if Substance Painter was connected when Houdini loaded the addon. | Shelf tool | What it does | |---|---| | Dousen: Export HDA | Saves the selected node’s HDA to the `HDAs` folder under the source root and publishes it as a `mesh.export` event. | | Dousen: Export VAT | Renders the selected ROP network, which must be set up for vertex animation texture output, and publishes the textures and mesh together. | | Dousen: Export Alembic | Exports the selected node to the `Alembic` folder using the `export_presets.houdini` settings, and publishes it as a `mesh.export` event. | | Dousen: Validate | Runs the validators and prints the results to the console. There are no Fix buttons. | | Dousen: Material Setup | Opens a dialog where you pick one catalog material for the whole asset. | | Dousen: Send to Painter | Exports the selected geometry as an FBX file and sends it to Painter. | | Dousen: Send to Unreal | Does the same as Dousen: Export VAT. | | Dousen: File Status (P4), Dousen: Check Out, Dousen: Sync & Reload, Dousen: Revert Checkout | The Perforce actions. See Perforce actions in the DCC. | The three export tools don’t run validation, so run Dousen: Validate before you export. They do run the Perforce pre-flight described in Perforce actions in the DCC. If you haven’t tagged the scene, validation infers the asset type from the saved file path. When another application sends a mesh to Houdini, Dousen creates a `geo` node with a `file` SOP inside it. ## Auto-publish on save When auto-publish is on, each save publishes the checked instances that Dousen collects in the scene, the same ones the Publish tab lists. A save-triggered publish doesn’t run the validators. Dousen still checks instance names if your naming rule is set to error, and it stops if another user has a file locked. | Application | Where to turn it on | What a save publishes | |---|---|---| | Blender | Auto-publish on Save in the Dousen panel | One `mesh.export` event for each instance, or `animation.export` for an animation instance. | | Maya | Publish mesh.export on save in the Tools tab | One `mesh.export` event for each instance, or `animation.export` for an animation instance. | | 3ds Max | Publish mesh.export on save in the Tools tab | One `mesh.export` event for each instance, or `animation.export` for an animation instance. | | Substance Painter | Publish textures on save in the Tools tab | One `texture.export` event for each texture set, which needs a target Unreal mesh. | | Substance Designer | Not available | Nothing. | | Houdini | No toggle. A studio script can set the `dousen_auto_publish` user data on `/obj` to `1`. | One FBX export and `mesh.export` event for each instance, or `animation.export` for an animation instance. | The setting is saved in the scene, so check it when you open a different scene. Turn it on only after a manual publish gives the result you expect. After a save-triggered publish, check Publish history to see whether Unreal imported and saved the asset. ## Materials and Nanite Choose materials from the project catalog in the application’s material picker. The assignment carries texture bindings and parameter overrides to Unreal. In Designer, the Publish tab and Send to Unreal on the Export tab send it. The assignment also decides whether the Nanite or NonNanite validator category runs, as described in The Nanite / NonNanite gate. A geometry profile can still turn Nanite off. See Materials and textures and profile settings. ## Where the addons save their data Each addon saves convention tags, the material assignment, and the auto-publish setting in your source file, so they travel with it in Perforce. Designer saves them in sidecar files next to the package instead, so check those in with the package. | Application | Convention tags | Material assignment | Auto-publish setting | |---|---|---|---| | Blender | Scene property `dousen_convention_tags` | Scene property `dousen_material_assignment` | Scene property `dousen_auto_publish` | | Maya | `fileInfo` entries that start with `dousen_tag_` | `fileInfo` entry `dousen_material_assignment_b64` | `fileInfo` entry `dousen_auto_publish` | | 3ds Max | File property `dousen_convention_tags` | File property `dousen_material_assignment` | Root node `appData` key `1001` | | Painter | Project metadata, `Dousen` namespace | Project metadata, `Dousen` namespace | Project metadata, `Dousen` namespace | | Designer | `.dousen-tags.json` | `.dousen-material.json` | Not available | | Houdini | `/obj` user data `dousen_convention_tags` | `/obj` user data `dousen_material_assignment` | `/obj` user data `dousen_auto_publish` | ## Open a file in a running DCC A `dcc.open` event with a `file_path` opens that file in a running Houdini, Substance Painter, or Substance Designer session. Blender, Maya, and 3ds Max don’t handle the event. For the event format, see dcc.open. ## Perforce actions in the DCC Each addon shows the Perforce status of the current scene and lets you check it out, sync it, and revert it. Use the Perforce tab in the Qt panels, the File Status (P4) sub-panel in Blender, or the Perforce shelf tools in Houdini. Each button is available only when it applies to the file’s current state. In a project with a separate source repository, the scene and the Unreal files can use different Perforce servers. | Action | Use it when | What to check afterward | |---|---|---| | Check Out | You want to edit an existing source file. | The file is open in the task’s changelist for its Perforce server. | | Sync & Reload | The file isn’t at the latest revision. Dousen asks you to confirm because the reload discards unsaved changes. | The loaded scene is the revision you expect. | | Revert | You want to discard your changes to an open file. Dousen asks you to confirm. | The scene matches the restored file. | | Refresh | You want to read the lock state again. | The status line shows the current state. | Blender and Houdini use slightly different button names. See Blender and Houdini. Before a publish exports, Dousen runs a Perforce pre-flight. This applies to publishes from Blender, Maya, 3ds Max, Substance Painter, and Substance Designer, to Painter’s save-triggered publish, and to the Houdini Dousen: Export HDA, Export VAT, and Export Alembic tools and Houdini auto-publish. If another user has one of the files locked, the publish stops and names the lock. Otherwise Dousen opens the scene and the files from your last export for edit in the task’s changelist, and adds newly created files after the export. Lock failures appear in Publish history. If you restart the DCC, the first publish afterward doesn’t know the previous outputs, so check those out yourself if your workspace is read-only. Painter and Designer publishes also run the naming check first. A publish doesn’t submit anything. Submit the task’s changelist afterward, as described in Perforce. ## Which rules run Dousen runs the rules from your project’s compiled conventions for each instance’s asset type and taxonomy. An instance with no type runs only the universal naming checks. The material assignment decides which Nanite category runs. For the rule reference, see Asset validation. ## If the panel or publish is missing - Launch the application through DousenDesktop and check the executable path in Settings → DCC Apps. - If the panel header says Cannot connect to Dousen Desktop, open Desktop. The panel reconnects automatically. - In Desktop, check the connected-app chips and the failed stage on the Publish history tab, and read the Logs tab. Publish history doesn’t list exports from the Houdini shelf tools, Painter’s own export dialog, or the export-only buttons on Designer’s Export tab. For those, use Show connection events. - If the instance list is empty, make sure your scene has one of the structures in What becomes an instance?, then click Reset. - Check the project’s source root, workspace, and target Unreal project. For more help, see Troubleshooting. To extend the addons, see Loading studio tools and the Bridge API. Previous ← Desktop app Next Publishing assets → ## Desktop app — Dousen URL: https://dousen.io/docs/desktop.html Summary: The Dousen desktop app: system-tray bridge for DCC events, Jira task panel, Perforce status, and DCC launcher. Updated October 2026 Describes DousenDesktop: how to sign in, what the main window shows, how to launch your DCCs, and how to configure and update the app. DousenDesktop is a system-tray app that runs on every artist machine. It shows your Jira tasks, opens and submits their Perforce changelists, and launches your DCCs with the Dousen addon loaded. It also runs the local bridge relay that the DCCs and Unreal use to exchange events. ## Start and finish an artist session - Open DousenDesktop from the tray, sign in to your studio, and select the project. In Settings, check the project’s source root, workspace, and Unreal project. - In My tasks, select the Jira issue you’re working on. Check its key and linked changelist before you open files for edit. - Launch your DCC from the apps bar. If it isn’t there, set its executable under Settings → DCC Apps. Open your Unreal project as usual. - Check that the apps show as connected. Then work in the source scene and publish as described in Publishing assets. - On the Publish history tab, check the result. Before you submit, check the saved assets in Unreal and the files in your changelist. - When you switch tasks or projects, check the new context in each running app. Relaunch an app under the new project if its launch paths or credentials need to change. ## Run the setup wizard The first time DousenDesktop runs on a machine, a full-window setup wizard opens before the tray icon and main window appear. After a welcome page, it has six steps: - Server: Dousen Cloud or a self-hosted URL. - Jira: base URL, email, and API token. - Version Control: Perforce, or Git / Skip for now. - Workspace: the Perforce depot path and client mapping. Desktop skips this step if you choose Git. - Unreal Project: browse for a `.uproject` file or let Dousen find one. - DCC Applications: scan for installed DCCs to register. The Quick start walks through each step, including how Desktop creates the Perforce workspace. The wizard doesn’t open again by itself. To run it again, for example to point a machine at a different server or Perforce workspace, click Re-run Setup on the sign-in screen. ## Signing in If DousenDesktop has no valid cached session, it shows the sign-in screen. What you enter depends on the deployment mode: - Cloud: sign in with your studio account email and password, or click Sign in with Browser. If your account belongs to more than one studio, the Choose Studio dialog lists each studio and your role in it before the sign-in completes. - Self-hosted: enter your email and password. Desktop checks them against your studio’s DousenCore. Sign in with Browser opens the Dousen Cloud sign-in page in your default browser and waits for it to return to Desktop. If you close the tab or abandon the sign-in, the button resets after 5 minutes. Desktop refreshes tokens in the background, so an expired token doesn’t interrupt you. Dousen allows one active device per account. If you sign in on another machine, this machine notices at its next 60-second heartbeat or token refresh, shows Session active on another device. Please log in again., and returns to the sign-in screen. See Sessions, tokens, and single-device enforcement. For admins: a person who signs in with their own account on a shared machine, such as a review station or a render box, is signed out of their own workstation. Give a shared machine its own Dousen account and license seat. ## The main window The main window opens after you sign in. To open it later, click the tray icon. | Region | What it does | |---|---| | Header | The project picker, the Settings button, and the Sign Out button. The project you pick decides which conventions, validators, and pipeline settings your DCCs load. | | Apps bar | One tile for each configured application, plus Add app, which opens Settings on the DCC Apps tab. A tile shows a green dot while that app is registered on the bridge. See Launching DCCs. | | Publish summary | The latest publish with its destination and status. Review N needing attention opens the failed and unconfirmed results in Publish history. When nothing needs attention, the button says View publish history. | | My tasks tab | Your assigned Jira issues, with a detail pane and changelist buttons. See My tasks and Jira tasks. | | Publish history tab | Connected apps and the result of each publish. See Publish history and Follow a publish in Publish history. | | Logs tab | The app’s own log, with a Clear button. | | Status bar | On the left, the Perforce state: `P4: `, `P4: (classic)`, `P4: not connected`, or `P4: connection unavailable`. On the right, the app version. See Perforce. | Closing the window hides it to the tray, and the bridge relay and background polling keep running. To exit, choose Quit in the tray menu. ### My tasks Search by Jira key or title, and use the status filter to narrow the list. Click Clear filters to reset them. My tasks loads your open issues 50 at a time. Click Load more tasks for the next page; automatic refresh pauses until you click Refresh. For the Jira query and the task details, see The My tasks tab. When you select a task, Desktop shows its description on the right and sends the task to the connected DCCs, so select the project and task before you launch your application. The detail pane has these buttons: - Open in Jira opens the issue in your browser. - Open changelist opens a Perforce changelist for the task. It is disabled when one already exists. - Submit changes opens a dialog for the submit message, then submits the task’s changelist. - Restore shelved changes restores the most recent shelved changelist for the task into your workspace, if there is one. The tab polls Jira every Task poll interval (Settings → Connection, 30 seconds by default) and reloads the shelved-changelist row on every poll. If Jira is unreachable, Desktop polls less often: | Backoff level | Poll interval | When it applies | |---|---|---| | 0 (normal) | The configured interval | The default. Desktop returns to it as soon as a fetch succeeds. | | 1 | The longer of the configured interval and 60 seconds | The first network failure, when Jira sends no HTTP response at all. A rejected sign-in stops polling instead (see below). | | 2 (maximum) | The longer of the configured interval and 5 minutes | Another failure while Desktop is already backed off. | While Desktop is backed off, one banner reads Offline — can’t reach Jira (reason). Retrying automatically. instead of an error for each poll. When the connection returns, the banner clears and Desktop shows Connection restored. If Jira rejects your credentials, polling stops and the message Jira sign-in failed — check your Jira email and API token in Settings. appears. Fix the token in Settings → Jira to resume. At startup, Desktop shows the last task list it saved to disk until the first fetch finishes, so your tasks appear even if Jira is briefly unreachable. ### Publish history The Publish history tab shows a chip for each connected application, followed by the result of each publish. For what each status line means, see Follow a publish in Publish history and Recover from a failed publish. Click Show connection events to list the last 20 events that the bridge relay handled, with their time, event type, and source and target application. ### Logs The Logs tab shows the app’s own log, up to 2000 blocks, with a Clear button. Look here first when a launch or a bridge event doesn’t do what you expect, for example to tell a connection problem from an import error. ## The tray icon | Menu item | What it does | |---|---| | Open Dousen | Shows and focuses the main window. Clicking the icon does the same. | | Manage Account… | Opens `/portal/account` in your browser. If no server is configured yet, it shows a notification instead. | | Check for Updates | Checks for an update now. See Automatic updates. | | Quit | Exits the app. Closing the window only hides it. | While apps are connected to the bridge, including Unreal, the icon shows a green badge with their number, or `9+` for ten or more. The badge updates every 3 seconds, and the tooltip lists the connected apps. ### Notifications Desktop shows a notification for two kinds of bridge event: - Mesh exported or Texture exported, with the file name and source app. - Opening in DCC, when another app such as Unreal asks Desktop to open a file. Desktop collects events for 2 seconds after the first one, then shows one summary, such as 3 asset(s) exported, 1 DCC open request(s). A large publish doesn’t produce a notification for every file. ## Launching DCCs Launch DCCs from the apps bar. A DCC that you start another way has no Dousen addon. Desktop passes the addon its project, task, sign-in, and bridge details in environment variables, which studio scripts can also read. See Loading studio tools. Desktop also sets `P4PORT`, `P4USER`, and `P4CLIENT` for the source repository’s Perforce connection, `DOUSEN_P4_ROUTES` for the project’s Perforce routes, and `DOUSEN_FBX_ROOT` when the project has a separate FBX location. See Source repositories. Executable paths come from Settings → DCC Apps. Use Discover DCCs to fill them in automatically or enter them by hand. If a launch fails with Executable not found, correct the path there. Desktop doesn’t open your Unreal project. Open it as usual while Desktop is running and signed in. If you add Unreal Editor to the apps bar, its tile shows a green dot while Unreal is connected. When another app publishes a `dcc.open` event, Desktop opens the file in a DCC. Most of these events come from Unreal’s Open in DCC command in the Content Browser. Desktop looks up the asset’s source record in DousenCore and finds the local path from where the file is stored: - Perforce: Desktop runs `p4 sync` and then `p4 where` to get the path in your workspace. For an asset from a separate source repository, Desktop syncs the file through the source route. - Google Drive or OneDrive: Desktop joins the mount path from Settings → Connection with the stored relative path. - Local: Desktop uses the last known path. Desktop then finds the application whose ID matches the event’s preferred DCC in Settings → DCC Apps and launches it with the file. ### If a DCC doesn’t open If a DCC doesn’t open after a `dcc.open` event, check the Logs tab first. It records why Desktop stopped: - Could not resolve local path for source asset: the mount path or the Perforce workspace isn’t configured. - Source file not found on disk: the resolved path doesn’t exist yet. This is common while Google Drive or OneDrive is still syncing. - No registered DCC found for id: no application in Settings → DCC Apps matches the ID the event asked for. Then click Show connection events on the Publish history tab. If the event isn’t listed, the source app didn’t publish it, or it uses a different relay port. ## Settings dialog Click Settings in the header to open the Settings dialog, which holds this machine’s settings. Project-wide conventions, validator rules, and pipeline settings are in the web portal. See Settings reference. | Tab | Fields | |---|---| | Connection | Server URL (read-only for Dousen Cloud accounts); Request timeout (1–120 seconds, default 10); Task poll interval (5 seconds to 1 hour, default 30); Bridge relay port in the Bridge group (1024–65535, default 8766); the Google Drive and OneDrive mount paths; and Test Connection. The relay port sets the port of the RPyC bridge relay. | | Support | Export Support Bundle… saves a small JSON status snapshot on your machine. The snapshot excludes credentials, account details, configuration, logs, file paths, asset data, and raw error messages. Review the file before you share it with support. | | DCC Apps | The list of configured applications, with Add, Edit, and Remove (ID, name, executable, icon, launch arguments, and environment variables). Also Discover DCCs, which adds installs it finds, and Pulse connected indicator for the apps-bar dots. If your installer includes it, Install DousenClips — Maya animation clip exporter appears too. | | Projects | Your local settings for each project. They are stored per user and not synced to the server: the `.uproject` path, the source root and its location type (local disk, Perforce, Google Drive, or OneDrive), and the Perforce server and workspace. For a project with a separate source repository, the Source Repository group also has your P4 user, workspace, and local root, and a Sign in to source Perforce button. The source server comes from DousenCore. See Source repositories. You can also create a new project on DousenCore from here. | | Unreal | A fallback `.uproject` path. Install into .uproject in the Install Plugin group copies the bundled DousenUE plugin into the project’s `Plugins` folder and registers it in the `.uproject`. The Headless Import (UE Closed) group has a checkbox to import with `UnrealEditor-Cmd` when Unreal isn’t running, and a path to that executable. | | Jira | Base URL, Email, API Token, and Test Connection. See Jira tasks. | ## Automatic updates Desktop checks for updates 5 seconds after launch, unless it checked within the last 4 hours, and then every 4 hours. To check right away, choose Check for Updates in the tray menu. Each check fetches a signed JSON manifest over HTTPS that lists the version, download URL, size, SHA-256 hash, and signatures for each platform. If there’s a newer version, the update dialog shows the version change and the release notes: - Skip Version hides that version from later automatic checks. A manual check still reports it. - Remind Later closes the dialog. - Download & Install downloads the installer. The button then becomes Install & Restart. Desktop trusts a download only if all three checks pass: - The SHA-256 of the downloaded file matches the manifest. - The Ed25519 signature on the manifest entry (version, platform, and hash) verifies against the public key built into the app. - The Ed25519 signature on the installer verifies against the same key. Desktop also refuses the update if the manifest URL or the download URL isn’t HTTPS, the hash is missing, or the build has no signing key. Desktop saves the installer in an `updates` folder in the app’s local data folder. When you click Install & Restart, it checks the file again, runs the installer, and quits. On Windows, the installer runs silently from a hidden PowerShell script, asks for administrator approval unless the app is installed for the current user, and starts Desktop again afterward. On Linux and macOS, Desktop opens the file with the system handler. ## Working offline If Jira is unreachable, Desktop shows the saved task list and polls less often, as described in My tasks. If DousenCore is unreachable, Desktop saves two kinds of calls on disk and sends them later: | Queued operation | When Desktop queues it | |---|---| | `upsertSourceAsset` | The call that records a mesh or texture export can’t reach DousenCore. | | `openChangelist` | Opening a Perforce changelist for a task can’t reach DousenCore. | Both calls are safe to send more than once. Desktop removes a queued call when the server accepts it or rejects it with a 4xx error, so a refused call isn’t retried forever. Desktop resends the queue after you sign in, after a token refresh, and after another of these calls succeeds. It drops a queued call that was saved for a different server or studio. Desktop doesn’t queue `submitChangelist`, because it needs the changelist ID that the server assigned when the changelist opened. Submitting always needs a connection. If Desktop last reached a licensed DousenCore more than 14 days ago, which matches DousenCore’s license grace period, it refuses new operations instead of queuing them. Reconnect to a licensed server to use pipeline actions again. ## Pre-configure machines (admin) On a cloud studio, you can fill in the setup wizard’s server settings for artists with a config bundle: a small JSON file with the keys `org_id`, `control_plane_url`, and `server_url`. The rest of the wizard still runs. You can deliver the bundle in two ways: - `--config-url `: pass a link on the command line, or build it into an installer shortcut. Desktop fetches the bundle and applies it on startup. - Drop `dousen-config.json` in the working directory, the Downloads folder, the home folder, or the app’s configuration folder. Desktop uses the first file it finds and asks you to confirm before it applies it. The bundle URL, and the `control_plane_url` and `server_url` inside it, must use HTTPS. Plain HTTP is accepted only for `localhost` and `127.0.0.1`, for development. Applying a bundle switches the app to cloud deployment mode. Previous ← Quick start Next DCC addons → ## Documentation — Dousen URL: https://dousen.io/docs/index.html Summary: Dousen documentation: quick start, desktop app, DCC addons, Unreal Engine plugin, Jira and Perforce integration, naming conventions, and asset validation. Updated October 2026 Dousen links Jira tasks, Perforce changelists, and your DCCs (Blender, Maya, Houdini, 3ds Max, Substance Painter, and Substance Designer) with Unreal Engine. This page explains what runs where, lists the components and ports, and links to the guide for each role. Artists work in DousenDesktop, the DCC addons, and the Unreal Engine plugin. Project admins configure each project in the web portal of the studio server (DousenCore). ## Choose your workflow Start a studio How to create a project, install DousenDesktop, and verify one workstation. Publish an asset How to choose instances, validate them, and confirm the import in Unreal. Configure Unreal imports Import profiles, reimport behavior, and project import stacks. Set up studio materials How to create the material catalog in Unreal and let artists assign its materials. Use a separate source repository How to keep DCC source art in its own Perforce repository. Extend your pipeline How to load your own startup scripts, validators, and launch options in each DCC. Work from a Jira task How to connect to Jira, link a task to a changelist, and move the issue on submit. Find tools and plugins Standalone authoring tools and Unreal editor plugins from the Dousen family. ## Set up a studio - Create the project and set up one workstation. - Define names and folders, then test the validation rules. - If your project uses studio master materials, create the material catalog and report it to the project. - If art and Unreal use different Perforce repositories, set up a separate source repository. - Publish a test asset and reimport it before you roll out to the team. Artists can start with the daily Desktop workflow and their first DCC session. Developers building a studio tool should start with the Bridge API. ## What runs where A cloud studio uses all three parts below. A self-hosted studio runs only the studio instance and the artist machines. DousenControl and DousenCore use HTTP/JSON, and the bridge on each artist machine uses authenticated RPyC connections over TCP. | Part | Runs on | Purpose | |---|---|---| | Cloud control plane | Dousen’s cloud, port 8090 (DousenControl) | Manages studios (orgs), subscriptions, and Ed25519-signed license tokens, and assigns each studio to a DousenCore instance. | | Studio instance | A server, port 8080 (DousenCore) | The service every artist and DCC works with: the REST API, the web portal at `/portal/`, MariaDB, the Perforce connection, and a Jira webhook endpoint. It holds the changelists, users, conventions, and validation history. | | DCC bridge relay | Each artist machine, `127.0.0.1:8766` (inside DousenDesktop) | A relay that accepts connections only from the same machine. DCCs and Unreal use it to hand work to each other (publish, register, and receive events) without a round trip to the server. | ### Port reference | Port | Service | Reachable from | |---|---|---| | 8090 | DousenControl REST (cloud control plane) | Dousen’s cloud only. Every studio instance, including self-hosted ones, sends license heartbeats to `https://control.dousen.io` over HTTPS, so allow that outbound connection. | | 8080 | DousenCore REST and web portal (`/portal/`) | Every DousenDesktop and DousenUE install for that studio, on whatever host and network the admin exposes it on (see Self-hosted install). | | 8766 | DousenDesktop bridge relay (RPyC over TCP) | Loopback only (`127.0.0.1`): the DCC addons and the Unreal plugin on the same machine. The port isn’t reachable over the network, and it doesn’t serve HTTP. See Bridge API. | ### Cloud and self-hosted studios | Aspect | Cloud | Self-hosted | |---|---|---| | Who runs DousenCore | Dousen. DousenControl assigns each studio to an instance. | You, with the Docker Compose bundle in `deploy/self-hosted/`. | | Licensing | DousenControl issues and renews licenses automatically. | You set the license token, which Dousen signs with Ed25519, and Dousen’s public key. The instance verifies the license offline and allows a 14-day grace period after it expires. | | Signing in | Cloud SSO through DousenControl, with an optional browser sign-in (OAuth with PKCE). Accounts that belong to more than one studio get a studio picker. | A local password that the instance checks itself, or your LDAP/Active Directory server if you set `DOUSEN_AUTH_MODE=ldap`. | | Getting an account | During the free studio beta, accounts are created manually. See Quick start. | Install the stack, then create the first admin with `dousen-cli`. See Create the first admin. With LDAP, the first sign-in by a member of `DOUSEN_LDAP_ADMIN_GROUP` creates one. | ## Components | Component | Part | What it does | |---|---|---| | DousenControl | Cloud control plane | The SaaS control plane: orgs, tenants, subscriptions, Stripe billing, license issuance, and Kubernetes/Helm tenant provisioning. | | DousenCore | Studio instance | The REST backend. It stores changelists, users, naming conventions, and validation history, serves the web portal, talks to MariaDB and Perforce, and accepts Jira webhooks at `/webhooks/jira`. | | DousenDesktop | Artist machine | A Qt 6 system-tray app. It is a REST client of DousenCore and a direct Jira client, runs the DCC bridge relay, launches DCCs, tracks source assets, and updates itself. | | DousenUE | Artist machine (Unreal Engine 5 editor) | An editor plugin. It calls DousenCore’s REST API, receives bridge events from DousenDesktop, and reimports changed assets. It doesn’t talk to Jira. | ## Key concepts ### Tasks Dousen doesn’t store tasks. DousenDesktop fetches each artist’s issues from Jira with their own credentials. See Jira tasks. ### Changelists Each Perforce changelist opened through Dousen is keyed to a Jira issue key, such as `DOU-142`. If a project admin sets it up, submitting the changelist moves the issue to another status. See Perforce. ### The bridge A relay on each artist machine passes publishes from the DCCs to Unreal Engine, and gives every running DCC the active task and changelist. Studio tools can join it like the built-in addons. The Publish history tab in DousenDesktop shows whether Unreal imported and saved each asset. See Bridge API. ### Naming conventions Naming rules are written in YAML, or in Lua for computed rules, and stored per project in DousenCore. Every client uses the same compiled JSON document, so a name built in Blender matches the name Unreal expects. Clients cache it for 5 minutes. See Naming conventions. ### Validation The same document holds validators, which are checks that run in the DCC before export. A validator with severity `error` blocks the export, and a `warning` is advisory. See Asset validation. ### Licensing and accounts Each studio instance verifies its Ed25519-signed license offline, and keeps working for a 14-day grace period after it expires. Seats are limited by plan. An account signs in with a local password, an LDAP/AD directory, or cloud SSO, and is active on one device at a time. ### Roles A studio instance has three roles: `admin`, `producer`, and `artist`. Only `admin` can change conventions, validators, settings, and users in the portal. On a person’s first sign-in from a cloud org, an org `owner` or `admin` becomes an instance Admin, and a `member` becomes an Artist. After that, the role set in Dousen is kept. See User and auth management. ## All pages ### Getting started | Page | Covers | |---|---| | Overview | This page: what Dousen is, what runs where, the components, ports, and where to go next. | | Quick start | How to get an account, configure a project, install DousenDesktop, run the setup wizard, and verify that the first asset reaches Unreal. | ### User guide | Page | Covers | |---|---| | Desktop app | Signing in, the tray icon, task filters, application launchers, publish history, and auto-update. | | DCC addons | What the Dousen panel does in each of the six DCC addons (Blender, Maya, 3ds Max, Houdini, Substance Painter, and Substance Designer), and how Unreal Engine joins the bridge as a seventh application. | | Publishing assets | How to choose the instances to publish, validate them, publish from a DCC, and confirm the result in Unreal. | | Unreal Interchange | How Dousen imports published instances into Unreal Engine with Interchange, how reimport works, and how to set up import profiles and project import stacks. | | Jira tasks | How DousenDesktop fetches your Jira issues with your own credentials, and how submitting a changelist moves an issue to a new status. | | Perforce | Changelists keyed to a Jira issue, file-lock status in the DCC, and Perforce Streams. | | Source repositories | How to bind a project to a separate Perforce repository for DCC source art, and how artists work with it. | | Unreal Engine | How to install and configure the DousenUE editor plugin, how published assets are named and imported, and the Content Browser menus, such as Open in DCC. | ### Admin guide | Page | Covers | |---|---| | Naming conventions | How to write a project’s naming document in YAML or Lua, how the taxonomy works at any depth, and how clients cache the compiled result. | | Asset validation | Every built-in validator by category, the validator catalog, the Nanite and NonNanite rules, and how to write a custom validator plugin. | | Materials and textures | How to create the material catalog in Unreal, report it to the project, and check artists’ material assignments. | | Settings reference | Every project-level YAML document and scalar setting that you can edit in the web portal. | | Loading studio tools | How to run your own startup scripts, extra validator paths, and per-machine launch options alongside Dousen’s addons. | | User and auth management | Users and roles in DousenCore and DousenControl, the three sign-in modes, sessions and tokens, and how accounts are created. | | Self-hosted install | How to run DousenCore with the Docker Compose bundle: `install.sh`, the manual setup steps, and LDAP configuration. | ### Reference | Page | Covers | |---|---| | Tools and plugins | Standalone authoring tools and Unreal editor plugins from the Dousen family. | | Bridge API | Authenticated bridge requests and pushed events, for studio tools that join the bridge like a built-in addon. | | Troubleshooting | Fixes grouped by symptom and by where you see the problem, and where each log file is. | If something doesn’t work the way a page describes, see Troubleshooting, which is organized by symptom. Next Quick start → ## Unreal Interchange — Dousen URL: https://dousen.io/docs/interchange.html Summary: Configure Dousen Interchange profiles, review instance topology, preserve reimport policy, and install opt-in project import stacks. Updated October 2026 · Unreal / technical art Describes how Dousen imports published instances into Unreal Engine with Interchange, how reimport works, and how to set up import profiles and project import stacks. ## Set up an import profile (project admin) Import profiles need a current DousenCore. Cloud studios get it when the update is deployed. Self-hosted studios must update DousenCore. With a current DousenCore, saving conventions in the portal rejects an invalid profile and shows an error. If conventions saved earlier contain an invalid `interchange` block, the Conventions page warns that the block was ignored, and the rest of the conventions keep working. - Check that your conventions work and that one test mesh completes an ordinary Dousen publish. - In the project’s Conventions editor, add an `interchange` block with a profile, like the example under Named geometry profiles. Give the profile a unique name and include only the fields you need. - In the same document, declare an `import_profile` dimension and list the profile names as its `values`. Each value must match a profile name exactly, and the dimension can’t be `required`, because textures can’t carry the tag. DousenCore checks both when you save. Fix any error the portal shows. YAML`dimensions: import_profile: values: [authored_prop]` - In Blender, Maya, or 3ds Max, open New Asset (in Maya and 3ds Max, click Load Conventions first). Choose the profile in the Import Profile list and click Set Up Asset. The scene stores the tag, so every instance in that scene uses the profile. The list starts at (none). To give one instance a different profile, right-click it in the Publish tab and choose Set Import Profile (Maya and 3ds Max). The per-instance choice overrides the scene tag. - Publish a new test instance and check the Unreal settings it produces, such as collision, scale, and Nanite. An asset you already imported keeps the settings stored with it, so it can’t test a new profile. - Test an ordinary reimport and a topology change before you roll the profile out. Check the saved assets and the result in DousenDesktop. - If artists also import from the Content Browser by hand, install a project import stack. Profiles control geometry import settings. The material catalog lists the materials artists can assign and whether each one allows Nanite. Check both when you decide which assets use Nanite. ## How a new instance is imported When you publish a checked instance, Dousen checks it against your conventions before it creates any asset: the naming dimensions, allowed values, taxonomy, package names, and destination collisions. If any check fails, Dousen rejects the whole instance. A new import through the bridge needs the project’s conventions. Without them, the import fails with `Project conventions unavailable; fetch conventions before importing new assets`. If an instance has several meshes, one primary mesh gets the instance name, and a skeletal mesh takes priority. The other meshes get names from your conventions. Dousen adds convention and source metadata to each imported asset. The import is complete only after Unreal saves the required packages. An animation-only import needs the existing skeleton it targets. ## Reimport behavior When you publish the same instance again, Dousen reimports the meshes and animations that it recorded for the instance. Existing assets keep their asset paths and the naming and geometry settings stored with them. A reimport doesn’t rename an asset to match a newer convention, import new meshes, or delete removed ones. To add or remove meshes, use Review instance topology. A reimport uses the conventions stored with the asset. To use the current conventions instead, set `bRefreshConventionsOnReimport=true` under `[/Script/DousenUE.DousenProjectSettings]` in `Config/DefaultDousenUE.ini`. It is `false` by default. Existing asset names never change. See Configure the plugin. Reimport (sync source) in the Content Browser reimports only the asset you selected, and it doesn’t add or remove instance members. Assets imported with Epic’s legacy FBX importer stay on that importer. ## Review instance topology If you add or remove meshes in the source scene, use Review instance topology in the Content Browser to preview the change and approve it. - Publish the updated instance from the DCC so the export file is current. - In the Unreal Content Browser, right-click a mesh that belongs to the instance. In the Dousen section of the menu, choose Review instance topology. The command appears only for meshes that Dousen imported. - In the Dousen instance review window, read the list. Each Add: line is a new mesh. Each Retain removed source asset: line is a mesh that is no longer in the source. - If the window reports a naming problem or an occupied destination, resolve it and review again. - Click Apply reviewed changes. Dousen imports the additions and shows [Dousen] Instance reconciliation saved after Unreal saves the packages. - Check the new assets. Removed meshes stay on disk, so delete them yourself if you no longer need them. If the source file or the instance’s saved list of members changed after you opened the review, applying it fails with `Review is stale or invalid; preview the source again`. Open a new review. Reviewing instances that were imported before Dousen recorded their members For an older Dousen Interchange import, the first review adopts the members it can verify from the saved import data, and the window starts with Adopt verified members from saved import data. Dousen adopts a mesh from the same folder only when its saved Interchange node ID and its source file both match. If two assets match the same node, Dousen asks you to keep duplicate imports in separate folders. It can’t adopt assets that Epic’s legacy FBX importer created. If a node that you removed returns and collides with retained content, resolve the conflict yourself and review again. ## Named geometry profiles A named profile overrides the import defaults for the fields it declares, and every other setting keeps Epic’s default. There is no default profile. An instance uses a profile only if you select one with its `import_profile` tag, or through the Policy tags of an installed stack. JSON`{ "interchange": { "schema_version": 1, "profiles": { "authored_prop": { "nanite": false, "collision": "source", "normals": "import", "tangents": "mikk", "import_lods": true, "bake_meshes": true, "bake_pivots": false, "uniform_scale": 1, "animation_sample_rate": 60 } } } }` The example is a fragment. Add the `interchange` key at the top level of your full conventions document, next to `version: 3`. On its own it fails with a missing-version error. `authored_prop` is an example, so change its values to suit your assets. ### Profile settings reference | Setting | Accepted values | Behavior | |---|---|---| | `nanite` | `true`, `false` | If set to `false`, the catalog’s Allow Nanite can’t turn Nanite back on. Skeletal meshes don’t use the static-mesh Nanite path. | | `normals` | `import`, `recompute` | `recompute` makes Unreal recompute normals on import. | | `tangents` | `import`, `recompute`, `mikk` | `import` keeps the source tangents. `recompute` recomputes them. `mikk` recomputes them with MikkTSpace. | | `collision` | `none`, `source`, `box`, `sphere`, `capsule`, `convex18dop` | `none` turns off collision import and generation. `source` imports the collision meshes named in the source and generates no fallback. The other values generate that primitive. | | `import_lods` | `true`, `false` | LOD import requires `bake_meshes` to be `true`. | | `bake_meshes` | `true`, `false`. The default is `true`. | Applies the source scene’s transform to each mesh. | | `bake_pivots` | `true`, `false`. The default is `false`. | Applies the node’s pivot to the mesh vertices. It requires `bake_meshes` to be `false`. | | `uniform_scale` | A number greater than 0 and at most 100000 | Unreal’s Offset Uniform Scale, applied to meshes and animations. | | `animation_sample_rate` | An integer from 0 to 48000 | The sample rate in Hz for imported animation. `0` lets Unreal choose the best matching rate. | Because `bake_meshes` defaults to `true`, a profile that sets only `"bake_pivots": true` is rejected. Set `"bake_meshes": false` as well. If the profile isn’t valid, Dousen rejects the whole instance before it runs any factory. A profile isn’t valid if it has any of these: - An unknown profile name or `schema_version`. - An unsupported field. - A value of the wrong type or outside its range. - Bake, pivot, and LOD settings that don’t work together. Geometry profiles apply only to meshes and animations. If a texture’s tags include `import_profile`, Dousen rejects the import. ## Install a project import stack Imports that you start from the Content Browser don’t use your Dousen conventions or profiles until you install a stack. A stack is a named pair of pipeline assets that you select in Unreal’s Interchange import dialog. - Open the Unreal project with DousenDesktop running and signed in, so the plugin can fetch the project’s conventions. `bUseDousenImportPipeline` must be on, which is the default. See Configure the plugin. - If `Config/DefaultEngine.ini` is read-only, check it out first. The command doesn’t check it out for you. - Run the command in the Unreal console: TEXT`Dousen.InstallImportStack [dimension=value ...]` For example: TEXT`Dousen.InstallImportStack DousenProps /Game/Dousen/ImportPolicies/Props static_mesh category=Props` - Select the stack in the Interchange import dialog when you import a file. - Submit the new pipeline assets and `Config/DefaultEngine.ini` together. The command saves two pipeline assets, `Assets` and `Policy`, in the folder you give. It also adds the stack to `InstalledStacks` under `[/Script/DousenUE.DousenProjectImportSettings]` in `Config/DefaultEngine.ini`. Dousen builds the stack’s Policy tags from your `dimension=value` arguments, plus an `asset_type` tag that it sets from the kind. Supply every dimension that your conventions require. To attach a geometry profile to a `static_mesh` or `skeletal_mesh` stack, add `import_profile=`. If the tags don’t match your conventions, the command doesn’t install the stack. A new import through the stack reads its Policy asset, which you can edit. The command also refuses a stack name or a destination asset that already exists. If saving the assets or the config fails, it removes the new assets so you can try again. By default, Unreal skips the Interchange dialog for texture imports, so you can’t select a texture stack. To show it, open Project Settings and go to Interchange. Under Import Content, find Show Import Dialog Override and turn on the import dialog for Textures. Installing a stack doesn’t change this setting or any other Content Browser default. ## Unregister a stack or disable Dousen To unregister a stack, remove it from `InstalledStacks` under `[/Script/DousenUE.DousenProjectImportSettings]` in `Config/DefaultEngine.ini`, then restart the editor. Saved import data and pipeline assets refer to Dousen classes, so keep the plugin enabled for as long as you reimport those assets. Before you disable it, convert the affected assets to Epic’s native pipelines and check that they reimport while Dousen is still installed. Then remove the Dousen pipeline assets and registrations. ## Editor responsiveness and limits Topology previews, approved additions, Reimport (sync source), and bridge instance updates run in the background. Members of an instance that use compatible settings share one source translation. Members with different transform or bake settings are translated separately. Dousen refuses overlapping reimports of the same asset. Unreal still does some geometry and factory work, and saves packages, on its game thread, so a large FBX file can still stall the editor. Test with your own rigs and scenes. ## Troubleshooting | Symptom | What to do | |---|---| | `Project conventions unavailable` | Check the project, your sign-in, and the connection to DousenCore. Fetch valid conventions before a new bridge import. | | `Convention error: 'interchange.profiles..' must be …` when you save in the portal | DousenCore rejected the profile. Fix the field it names, using the settings reference. | | `Unknown import_profile`, `Unsupported or invalid import profile field`, or `Import profile has incompatible mesh baking, pivot, or LOD settings` | Check the profile name, `schema_version`, field types and ranges, and the bake and LOD rules in the settings reference. If the profile is valid, check that DousenCore is current. An older DousenCore doesn’t pass profiles to Unreal. | | `Review is stale or invalid` | Finish editing the source, then open a new topology review. | | `Added source node destination is occupied` | Resolve the naming or ownership problem. Don’t overwrite retained content to force the review through. | | The import isn’t confirmed | Check Unreal and the required package saves before you publish again. See Recover from a failed publish. | | `Check out the project config before installing a stack` | Make `Config/DefaultEngine.ini` writable through your source control workflow, then run the command again. | Previous ← Publishing assets Next Jira tasks → ## Jira tasks — Dousen URL: https://dousen.io/docs/jira.html Summary: Work Jira tasks from inside your DCCs — task lists, status transitions on changelist submit, and full ticket-to-asset traceability. Updated October 2026 Describes how DousenDesktop lists your Jira issues, how a task links to a Perforce changelist, and how DousenCore moves the issue when you submit. Dousen doesn’t store tasks, because Jira Cloud is the task system. Dousen uses two Jira connections: - Your personal connection is your email and API token in Settings → Jira. DousenDesktop uses it only to read issues into the My tasks tab. - A project connection is the base URL, project key, email, and API token that a project admin sets for the project in the web portal. DousenCore uses it to move the issue forward when a changelist is submitted. Saving or publishing an asset doesn’t change the issue. ## Use a Jira task for a publish - Connect your Jira account in Settings → Jira. See Connect your Jira account. - In the My tasks tab, select the issue. - If the task has no changelist, click Open changelist. - Launch the DCC from DousenDesktop and check that its panel shows the same task and changelist. - Publish the checked instances, check the result in Unreal, and click Submit changes. - If the project moves issues on submit, check the issue in Jira. If its status didn’t change, see Transition the issue on submit. ## Connect your Jira account In Settings → Jira, fill in these fields. The setup wizard asks for the same ones. Your Jira account must be able to browse your issues. | Field | Value | |---|---| | Base URL | Your Jira Cloud site, for example `https://yourstudio.atlassian.net`. | | Email | The email address you sign in to Jira with. | | API Token | A personal token from your Atlassian account (`id.atlassian.com` → Security → API tokens). The tab also has a Create or manage Jira API tokens link. | Test Connection sends `GET /rest/api/3/myself` with your email and token as HTTP Basic credentials. It shows Connected if Jira answers `200` and Failed otherwise. The test doesn’t save anything. DousenDesktop stores the token in its app-data folder, separate from your sign-in session. The file is obfuscated with a random per-install key, kept in a second file that only your account can read. This isn’t strong encryption. Jira requests go from your machine straight to Jira Cloud with Basic authentication. The only Jira data DousenDesktop sends to DousenCore is the issue key (for example `DOU-142`), when you work with a task’s changelist. ## The My tasks tab My tasks lists the issues assigned to you that aren’t Done, using this JQL query: TEXT`assignee=currentUser() AND statusCategory != Done` | Call | What it fetches | |---|---| | `GET /rest/api/3/search/jql` | The task list. Query parameters: `jql` (above), `fields=summary,status,priority,description,assignee`, `expand=renderedFields`, `maxResults=50`, and `startAt`. | | `GET /rest/api/3/issue/{key}` | The full detail of one issue, fetched when you select it. It uses the same `fields` and `expand` values. | My tasks loads your open issues 50 at a time. If more are available, click Load more tasks below the list to add the next 50. Issues you move to a Done status in Jira leave the list. DousenDesktop refreshes the list every 30 seconds by default. To change this, set Task poll interval in Settings → Connection to 5–3600 seconds. While extra pages are loaded, the automatic refresh pauses so it doesn’t replace them. Click Refresh to reload from the first page and resume it. Search matches the Jira key or the title, and Status filters by status. Both apply only to the issues that are loaded, so click Load more tasks to search further. Refresh fetches the list again. Select a task to see its status, Jira key (REF), PROJECT, TASK ID, linked changelist (CL), shelved changelist (SHELVED, see Shelving), and description. The description comes from `renderedFields.description`, so headings, lists, and images look as they do in Jira. DousenDesktop downloads description images (`/secure/attachment/...` URLs) with your credentials, keeps them in memory for the session, and scales down any that are wider than the pane. | Button | Action | |---|---| | Open in Jira | Opens the issue in your system browser. | | Open changelist | Opens a Perforce changelist for this issue. See Perforce. | | Submit changes | Submits the linked changelist. | | Restore shelved changes | Unshelves the most recently shelved changelist for this task (preview). See Shelving. | ## When Jira is slow or unreachable If Jira is slow or unreachable, the tab keeps showing the last known tasks, and DousenDesktop polls less often until Jira answers. If Jira rejects your credentials (401 or 403), polling stops until you save valid credentials. For the backoff intervals and exact messages, see My tasks and Troubleshooting. ## Link a task to a Perforce changelist Open changelist opens a Perforce changelist and links it to the issue key (for example `DOU-142`) in DousenCore. While the task stays selected, every DCC addon receives the task and changelist through the `task.context` bridge event, and your exports carry them. See DCC addons. DousenDesktop gets the task’s changelist state from DousenCore. After the list refreshes, Submit changes stays enabled and Open changelist stays disabled while the task has an open changelist. For how changelists are opened and submitted, see Perforce. ## Transition the issue on submit When you submit a task’s changelist, DousenCore can move the Jira issue to another status, using the project’s Jira connection. DousenDesktop doesn’t call Jira for this. A project admin sets up two things: - A project Jira connection. In the portal, open Projects, select the project, open Project settings, and find Jira Configuration. Enter the Base URL, Project Key, Email, and API Token, then click Update. The API token field is write-only. Leave it blank to keep the current token, or enter a value to set or replace it. - The `jira.on_submit_transition` pipeline setting, which names the transition to run. In Pipeline settings it is the Jira transition on CL submit field under Integrations. In the YAML it looks like this: YAML`jira: on_submit_transition: "In Review"` Then submit a test changelist for a task and check that the issue moves. After a successful submit, DousenCore lists the issue’s transitions (`GET /rest/api/3/issue/{key}/transitions`), picks the one whose name matches the setting (ignoring case), and runs it with a `POST` to the same URL. If no transition matches or the call fails, DousenCore logs the problem. The submit still succeeds, but the issue doesn’t move. Enter the name of the Jira workflow transition, which can differ from the status it leads to. For example, a transition called "Send to Review" can move the issue to a status called "In Review". To see your transition names, open Project settings → Workflow in Jira. DousenCore uses the project that was selected when the changelist was opened. If the changelist has no recorded project, it uses the project that DousenDesktop sends with the submit. If the project uses a separate source repository, the issue moves after the task’s last non-empty changelist is submitted. See Perforce. ## Inbound Jira webhook DousenCore accepts webhook events from Jira at `POST /webhooks/jira`. The `X-Hub-Signature-256` header must be `sha256=` followed by the HMAC-SHA256 of the raw body, computed with `DOUSEN_WEBHOOK_SECRET`. | Condition | Response | |---|---| | Valid `X-Hub-Signature-256` for `DOUSEN_WEBHOOK_SECRET` | 200 OK. DousenCore parses and logs the event. | | Missing or mismatched signature | 401 Unauthorized. | | Body isn’t a Jira webhook payload | 400 Bad Request. | | `DOUSEN_WEBHOOK_SECRET` is not set | 503 Service Unavailable. The endpoint rejects requests unless `DOUSEN_ALLOW_INSECURE_WEBHOOK=true` is set, which is for development only. | The endpoint doesn’t change any changelist or task state. To move issues on submit, use `jira.on_submit_transition`. Previous ← Unreal Interchange Next Perforce → ## Materials and textures — Dousen URL: https://dousen.io/docs/materials.html Summary: Create a project material catalog in Unreal, report it to Dousen, and assign materials and textures in your DCC. Updated October 2026 · Project admins and artists Describes how to create a material catalog in Unreal, report it to your Dousen project, and assign catalog materials and textures to source assets in a DCC. Project admins Create the catalog and report it to Dousen. Artists Assign a catalog material and bind its textures. ## Before you start - Project admin: an Admin sign-in, the project’s UUID, DousenUE enabled in the Unreal project, and permission to edit its content and configuration. - Materials: working Unreal materials that expose texture, scalar or vector parameters. The picker can’t override a texture that is wired into the graph without a texture parameter. - Artist: DousenDesktop signed in, the project’s source root and workspace configured, the DCC launched from Desktop, and the master materials synced into the target Unreal project. Material integration is a preview feature. Before you roll it out, run the test below with your studio’s engine and DCC versions. ## Create the catalog in Unreal The examples use a sample material, `M_PaintedMetal`, with texture parameters `BaseColor`, `Normal` and `ORM` and a scalar parameter `RoughnessMult`. Replace them with the parameter names your own materials expose. - Prepare a master material. On a working master material, expose the parameters that artists can override. Keep the existing parameter names. Compile and save the material. - Create a Data Asset in project content. In the Unreal Content Browser, create a Data Asset and select Dousen Material Catalog (`UDousenMaterialCatalog`) as its class. Save it in your project’s content, because the DousenUE plugin doesn’t contain content assets. For example, save it as `DA_MaterialCatalog` in `/Game/Dousen/`. - Add a Materials entry. Open the Data Asset and add an entry to Materials. Set Material to your master material. Give the entry a unique Id in lowercase with underscores, such as `painted_metal`, and a Display Name, such as Painted Metal. Set Allow Nanite for that material. It is on by default. - Populate the parameters. Click AutoPopulateFromMaterials. For each entry that has a Material, it fills in an empty Id and Display Name and adds a declaration for every texture, scalar and vector parameter the material exposes. It guesses each texture’s Content, SRGB, Compression and Match Keywords from the parameter name. It keeps values you filled in and never removes declarations. - Review and save. Check every guess, each scalar default and range, and each vector default (see the next section). Remove declarations you don’t need, then save the catalog and the master material. Don’t change an Id after artists have saved assignments that use it. ## Set up texture channels and parameters Each entry in Texture Slots maps one shader parameter to a texture channel: - Param Name is the exact Unreal parameter name. It isn’t the source filename or the mesh’s material-slot name. - Content describes what the pixels mean, whatever the parameter is called. A parameter called `DiffuseMap` or `ColorTexture` can have Content set to Albedo. - SRGB and Compression set how the catalog-driven importer treats the texture. - Match Keywords are lowercase filename fragments that Dousen uses to match exported files to the slot. The Content and Compression dropdowns list fixed choices from the plugin. Parameter names, labels and keywords come from your project. Review what AutoPopulateFromMaterials guessed, and correct Content where it’s wrong. | Parameter name | Content | SRGB | Compression | |---|---|---|---| | `BaseColor` | Albedo | Enabled | Default | | `Normal` | Normal | Disabled | NormalMap | | `ORM` | ORM | Disabled | Masks | In this example, use the keywords `basecolor` and `albedo` for BaseColor, `normal` for Normal, and `orm` for ORM. The channel order of a packed map must match the shader graph, because Dousen doesn’t repack image channels based on a filename. Auto-population can classify several packed-map names the same way, so check its result against how your textures are packed. Other texture content types The Content list also includes Roughness, Metallic, ARM, AO, Emissive, Opacity, Height, Mask and Custom. The Compression choices are Default, NormalMap, Masks, Grayscale and HDR. Data maps normally use linear sampling, so turn SRGB off for them and choose the compression that fits the data. Set Custom slots yourself, because Dousen can’t guess their settings from a name. ### Configure scalar and vector controls Expand Scalar Params and add an entry for each scalar parameter that artists may override. Set Name to the exact shader parameter name. Set Default, Min and Max to values that suit the graph, and enter a Label for the control that artists see. The label can differ from the parameter name and doesn’t rename the shader parameter. If you leave Label empty, artists see the parameter name. Vector Params work the same way: set the exact parameter Name, a Default linear color, and an optional Label. Save the catalog, then test an override on one imported Material Instance from the DCC picker. ## Connect the catalog to the project - Check out `Config/DefaultDousenUE.ini` in the Unreal project if it’s read-only, or create it if it doesn’t exist. Keep the settings that are already in it. - Under `[/Script/DousenUE.DousenProjectSettings]`, add `MaterialCatalog` with the Data Asset’s full object path, including the asset name after the dot. - Check `ServerScheme`, `ServerHost` and `ProjectId`. An editor launched from DousenDesktop takes the server, project ID and bridge port from Desktop instead, so select the same project in Desktop. - Restart the editor from Desktop while you’re signed in as an Admin, then save the catalog to trigger a report. INI`[/Script/DousenUE.DousenProjectSettings] ServerScheme=https ServerHost=core.example.com ProjectId=YOUR_PROJECT_UUID MaterialCatalog=/Game/Dousen/DA_MaterialCatalog.DA_MaterialCatalog` Set `ServerHost` to your studio’s DousenCore host and `ProjectId` to your project’s UUID. Don’t point `ServerHost` at the marketing website or the cloud control plane. Don’t put access tokens in project INI files, because Desktop supplies the current sign-in credentials. For the other keys and the HTTPS rule, see Configure the plugin. ## Verify the report and distribute it - In the web portal, click Projects, select your project, and click Materials. Check that each material’s ID, display name, path, texture declarations and parameters match the Data Asset. - If the page says "No material catalog has been reported for this project yet," see Troubleshoot catalog and assignment problems. - Submit the catalog `.uasset`, the master material and its dependencies, and `Config/DefaultDousenUE.ini` to source control. Other workstations need these files, even though the picker gets the catalog from Core. - On a test artist workstation, sync those files, launch the project, and check that the expected material appears in the DCC picker. Unreal reports the catalog to Core when the editor starts, when you save the catalog, when the catalog file changes on disk (for example after a Perforce sync), and every five minutes. It skips a report if nothing changed. Core rejects a report that is older than the catalog it already has as stale. DCCs cache the catalog for five minutes, so Load Materials can return an older copy. ## Assign a material in the DCC - Open the source. Check the project and task in Desktop, then open the saved source file. Note the mesh’s material-slot names (or the Substance Painter texture-set names), which receive the assignments. They are different from shader parameter names such as `BaseColor`. - Load the catalog and choose a material. In the Qt picker, click Load Materials, then choose a material for each slot in Slot Materials. The slot’s texture and parameter fields appear under Material Details. In Substance Painter, the list is Texture Set Materials on the EXPORT tab. Blender uses native controls (see the Blender workflow), and Houdini uses its material setup tools. - Bind textures and set overrides. Under Material Details, click Browse… next to each texture parameter and choose its source image, for example the base color, normal and packed ORM images. After an export, Dousen can fill in unset texture paths by matching filenames to the Match Keywords, so check them. Enter only the scalar and vector overrides you want. - Save, validate and publish. Save the source, which saves the assignments with it. Collect the instance again, check its type and destination, and click Validate. In Substance Painter, if the mesh didn’t come from a Dousen export with its sidecar, open the EXPORT tab, enter the Unreal object path in Target Unreal mesh (for example `/Game/Props/S_Crate.S_Crate`), and click Use target mesh before you publish texture sets. Publish the checked instances. - Check the result in Unreal. Wait for Desktop to confirm that Unreal imported and saved the asset. Open the imported mesh and its Material Instance, and check the parent material, slot binding, texture parameter values, SRGB and compression settings, and overrides for each slot. If you choose a different material for a slot, the Qt picker clears that slot’s texture bindings and overrides, so bind them again before you publish. Each DCC saves assignments with the source file in its own way. ## Test one asset before rollout - The portal and the DCC show the same material ID and declarations. - The master material resolves in the target Unreal project. - Each mesh slot gets the intended Material Instance, and each image is bound to the intended parameter. - Base color is sampled as color, and the normal and packed data maps use the intended linear and compression settings. - After you change a scalar override and publish again, the new value appears in Unreal. - After you reopen the source, its assignments are still there, and Desktop confirms that Unreal saved the new imported packages. ## How the import sets Nanite When Unreal imports a static mesh that has a material assignment, it turns Nanite on if every assigned catalog material has Allow Nanite on, and off if any has it off, with these exceptions: - A geometry profile that disables Nanite keeps it off, whatever Allow Nanite says. See geometry profiles. - If an assignment doesn’t match a catalog entry (for example, it falls back to a material path), Unreal leaves the mesh’s Nanite setting alone. - Skeletal meshes have no Nanite settings, so Unreal skips them. The DCC uses the same material lookup to choose between the Nanite and NonNanite validators. See The Nanite / NonNanite gate. ## Update an existing catalog - Sync the latest catalog and check it out before you edit it. Coordinate your edits with the other project admins. - Keep existing Ids when you change display names or add parameters. If you move a master material, update the reference and check that it resolves on a second workstation. - After you change a shader’s interface, click AutoPopulateFromMaterials and review the declarations. Remove renamed or deleted parameters yourself, and set the range and content type for new ones. - Save the catalog, check the new values in the portal, and submit the content and config changes. Artists can refresh or relaunch their DCC once the catalog cache expires. - A catalog update doesn’t rewrite existing Material Instances, so review the existing source assignments and republish a test instance. ## Troubleshoot catalog and assignment problems The Data Asset class is missing Check that DousenUE is enabled in this project and restart the editor. Fix any plugin build or load errors first. The Materials tab says "No material catalog has been reported for this project yet" Look for `LogDousenUE` messages in Unreal’s Output Log. Check the configured object path, the project UUID, the selected project and the server connection, then save the Data Asset while signed in as an Admin. An HTTP 401 means the editor has no valid sign-in credentials, and an HTTP 403 means the signed-in user isn’t an Admin. Fix that in Desktop, then restart the editor or save the catalog again. The portal is current but the picker shows an older catalog Check that the DCC was launched for the same project. Wait for the five-minute cache to expire and load again, or restart the DCC. In Blender, you can click Refresh Material Catalog instead. If a fetch fails, the DCC keeps showing the last catalog it loaded. The report is rejected as stale Core already has a newer saved catalog. Sync the Data Asset and merge in the other admin’s changes before you change it again. Unsaved edits block an update from a sync If the catalog file changes on disk while the loaded package has unsaved edits, the editor skips the report. Save your edits or reload the version you want, then check the portal again. Textures are missing or assigned to the wrong channel Check the source paths, shader parameter names, mesh-slot names, filename keyword matches and packed-map order. Rebind the incorrect fields, validate, and publish a test instance. The material parent is missing in Unreal Sync the referenced material and its dependencies into the target project. The catalog stores only the material’s path, so it doesn’t copy the asset to other machines. For more, see Publishing assets, DCC addons and Unreal Engine. Previous ← Asset validation Next Settings reference → ## Perforce — Dousen URL: https://dousen.io/docs/perforce.html Summary: Dousen and Perforce: automatic changelists tied to Jira tickets, file lock visibility in every DCC, and streams support. Updated October 2026 Describes how Dousen links Perforce changelists to Jira tasks, sets up your workspace, and shows file locks in your DCC. Also covers shelving and the server connection. DousenDesktop runs `p4` on your workstation, under your own Perforce user and workspace, to open and submit each task’s changelist and to restore shelved changes. Desktop asks DousenCore to authorize each operation and reports the result afterward, so Core can keep the changelist keyed to the Jira issue. Desktop and every DCC addon also run local `p4` commands for lock status, checkout, sync, and revert. ## Work on and submit one task You need the Perforce command-line client, a signed-in Perforce user, a workspace that maps your source and project files, and a selected Jira task. - In DousenDesktop, select the project and the Jira issue, and check the Perforce connection in the status bar. - If the task has no changelist yet, click Open changelist in the task’s detail pane. Desktop creates a numbered changelist in your workspace with `p4 change -i` and reports the number to Core. If the task already has an open changelist, Desktop reuses it instead of creating a duplicate. - Sync the submitted source files you need before you edit. To edit an existing file, click Check Out in the DCC panel. A new file is added to Perforce (`p4 add`) when you create it with Dousen’s new-asset setup, or you can add it in P4V after you save it under a mapped path. - Check the lock status in the DCC panel. If another user has the file locked, coordinate with them instead of publishing over their work. - Save, validate, and publish. Exports from any DCC addon go to the task’s changelist through the live task context. Check the result in Unreal, and make sure the changelist holds the exported files, sidecars, and changed Unreal packages that your project needs. - Click Submit changes. In the Submit Changelist dialog, enter a message of at least 5 characters and click Submit changes. Desktop sets the description, runs `p4 submit -c `, and reports the result to Core. - Check the submitted changelist in Perforce and any Jira transition. The submit fails if the task’s changelist has no opened files, because Desktop never moves files out of the default changelist. Move the files you want into the task’s numbered changelist in P4V first. A confirmed publish doesn’t mean the changelist was submitted. ## Automatic workspace from the depot path Your admin sets a `depot_path` for each project, for example `//depot/MyGame/...`. In the setup wizard’s Workspace step, click Check. Dousen runs `p4 client -o`, `p4 where`, and `p4 info` for that path. - If a workspace already maps the path, Dousen fills in the local root and workspace name and reports Already mapped in workspace "" with the local path. - If the path isn’t mapped, a creation form appears. Choose a local root and a workspace name (the default is `_`), then click Create Workspace. Dousen pipes a client spec into `p4 client -i`. Before it creates the workspace, Dousen runs `p4 streams` to check whether the depot path is a stream root. If it is, Dousen writes a stream workspace, with a `Stream:` field in the client spec. Otherwise it writes a classic client spec with a `View:` mapping. The confirmation names the type: Stream workspace "" created or Classic workspace "" created. If the stream check fails, Dousen shows an error and doesn’t create a workspace. The workspace for a separate source repository uses the same check. Onboarding doesn’t sync the workspace. The confirmation says "… created. Sync it from P4V or UnrealGameSync before continuing." Run your first sync before you open any DCC. ## Streams Dousen detects streams from the `clientStream` field of `p4 info`, so there’s nothing to configure. After you sign in, the DousenDesktop status bar shows one of these: - `P4: ` is a stream workspace. Hover over it to see the workspace name and the server version. - `P4: (classic)` is a classic depot. - `P4: not connected` means Perforce didn’t report a workspace. - `P4: connection unavailable` means the check failed. Hover over it to see the reason. The Dousen panel in each DCC runs the same check and shows a short version next to your file lock status: `Stream: ` for a stream workspace, or `Classic depot` otherwise. ## File locks inside your DCC The Dousen panel in Blender, Maya, 3ds Max, Houdini, Substance Painter, and Substance Designer shows live Perforce status from `p4 fstat`, through P4Python if it’s installed or the `p4` command line otherwise. You can check out (`p4 edit`), revert (`p4 revert`), sync (`p4 sync`), and add (`p4 add`) files under your own Perforce user. Checkout and add use the active Jira task’s changelist, or Perforce’s `default` changelist if no task is active. The status refreshes about every 30 seconds. Each file shows one of these lines: | Status | Meaning | |---|---| | Locked by (CL n) | Someone else has the file checked out exclusively. | | Opened by | One or more people have it open without an exclusive lock. | | Locked by you | You hold the Perforce lock, from an exclusive checkout or `p4 lock`. | | Not at latest (have r, head r) | Your local copy is behind the depot. | | Available | Nobody else has the file open or locked, and your copy is current. | | P4 error: or Not in Perforce | Perforce can’t answer, because the server is unreachable or the file isn’t in the depot. | A publish also stops before it exports if another user has locked a file that the export would write. ## Shelving and unshelving In the My tasks detail pane, Desktop lists the shelved changelists that Dousen opened for the selected task in your workspace, which it recognizes by the Dousen markers in their description. It then enables Restore shelved changes, which runs `p4 unshelve -s -c ` for a pending changelist. Desktop doesn’t pass `-f`, so it never overwrites a writable local file. Restoring shelved changes from DousenDesktop is a preview feature. Plain `p4 shelve` and `p4 unshelve` work as usual. Don’t build a team workflow around this feature until it’s generally available. ## Jira transition on submit If your project admin has set up a project-level Jira connection and `jira.on_submit_transition`, submitting a Dousen changelist moves the linked Jira issue forward, for example to review. The setting takes a transition name, which can differ from the status name. For setup, see Jira tasks. ## Server connection (admin) DousenDesktop runs the Perforce commands under each artist’s own Perforce user, so DousenCore doesn’t need network access to your Perforce server or credentials for it. Core still has its own Perforce connection, set with the environment variables below, for the older server-run routes in the endpoint reference. Those routes serve Desktop builds that predate local changelists, and Desktop setups where none of the Perforce server, user, and workspace is configured. | Variable | Purpose | |---|---| | `DOUSEN_P4PORT` | Perforce server address. | | `DOUSEN_P4USER` | Service user the server acts as. | | `DOUSEN_P4CLIENT` | Service workspace for the server’s changelist operations. | | `DOUSEN_P4PASSWD` | Optional. If unset, Core relies on its environment and the P4 ticket file. | ## Separate source-art repositories A project can keep source art in a second Perforce workspace, which can be on a different server, with sparse on-demand sync. Source files and Unreal files then get separate changelists, and the Jira transition waits until every non-empty changelist for the task is submitted. A submit across two servers isn’t atomic, so check both changelists afterward. See Source repositories for the admin binding, onboarding, the FBX location, and recovery after a partial submit. ## Changelist descriptions Dousen keeps the Jira key in each changelist description, and DousenCore stores each changelist under that `jira_key`. | Opened by | Description while open | After submit | |---|---|---| | DousenDesktop | The Jira key, then two marker lines: `[Dousen:]`, which holds Core’s id for the changelist and not the Perforce number, and `[DousenProject: Task:]` | Your message, followed by the same two marker lines | | DousenCore (server-run routes, single service workspace) | `[dousen ] ` | `[dousen ]`, followed by your message | Dousen uses the markers to find a changelist again, so an Open or Submit that didn’t finish, for example after a lost reply, doesn’t create a duplicate. For changelists that Desktop opened, the markers stay after submit, so the Jira key stays in the depot’s submitted history. A changelist opened through the server-run route keeps its `[dousen ]` marker in front of your message. ## Endpoint reference These endpoints need a signed-in JWT. Desktop or a DCC panel normally calls them, so the table is mainly for scripting and troubleshooting. Desktop’s local operations use `POST /api/vcs/desktop/prepare` and `POST /api/vcs/desktop/complete`. Core records the workspace and result that Desktop reports and doesn’t check them against the Perforce server. | Endpoint | Request body | Response body | |---|---|---| | POST /api/vcs/open | `{"jira_key":"DOU-31","project_id":""}` | `{"changelist_id":"","vcs_changelist_id":""}` | | GET /api/vcs/pending?jira_key=DOU-31 | — | `{"changelist_id":str|null,"vcs_changelist_id":str|null}` | | POST /api/vcs/submit | `{"changelist_id":"","message":"...","project_id":""}` | `{"submitted_vcs_changelist_id":"","files_submitted":}` | | GET /api/vcs/info | — | `{"is_stream":bool,"stream_name":str|null,"stream_root":str|null,"server_version":str|null,"client_name":str}` | | GET /api/vcs/shelved?jira_key=DOU-42 | — | `{"shelved":[{"changelist_id","description","user"}]}` | | POST /api/vcs/unshelve | `{"changelist_id":""}` | `{"changelist_id":""}` | - `POST /api/vcs/open` is idempotent. If the task already has an open changelist that the server opened, it returns that one. - Submit and unshelve return `200` only to the user who opened the changelist or an Admin. Anyone else gets `403 Forbidden`. - The server-run `/api/vcs/unshelve` runs `p4 unshelve -s -f`, and `-f` overwrites a writable local copy. - The server-run open, submit, and unshelve refuse a task whose changelist Desktop opened, with `409`. - There’s no changelist-level revert endpoint. Revert is per file, and the DCC addon runs it locally. - There’s no `/api/changelists/...` endpoint. A DCC addon gets the task’s changelist number from the `task.context` bridge event that Desktop sends when you select a task. Previous ← Jira tasks Next Source repositories → ## Publishing assets — Dousen URL: https://dousen.io/docs/publishing.html Summary: Publish selected DCC instances, interpret validation and import results, and recover failed or unconfirmed publishes. Updated October 2026 · Artist workflow Describes how to publish instances from a DCC to Unreal, how to fix validation errors, and how to follow and recover a publish in DousenDesktop. ## Worked example: publish a crate and leave the pallet This example uses a saved scene with two instances, a crate and a pallet. Names and folders come from your project’s conventions. Screenshots on this page use a sample project. - Prepare DousenDesktop, the DCC, and Unreal as described in Before you publish. - In the DCC, open the Publish tab. Check the crate and clear the pallet. If the list doesn’t show your objects, click Reset. - If the crate’s type is wrong, right-click it and choose the type under Set Type. Point to the crate’s name to see its Unreal destination. If your conventions require other tags, such as a variant, set them with Set Up Asset when you create the asset. - If your project uses a material catalog, assign a material to the crate. See Materials and textures. - Click Validate. If the crate fails, expand the failed rule, fix the source, click Reset if you changed the scene structure, and validate again. - Click Publish. In DousenDesktop, watch the crate in Publish history until it shows Imported and saved in Unreal, then open the asset in Unreal. - Change the crate’s geometry, save, and publish the same instance again. The existing Unreal asset reimports. The pallet stays out of both publishes. If you later add a mesh to the crate instance, a normal reimport doesn’t import it. Use Review instance topology in the Unreal Content Browser instead. ## Before you publish - Sign in to DousenDesktop and select the correct studio and project. - In Settings, check the project’s source root, Perforce workspace, and Unreal project path. - Select the Jira task, check its changelist, and launch the DCC from DousenDesktop. - Save the source scene. Set the instance’s type, convention tags, and material assignment if your project uses them. - Keep the Unreal editor for the project open. If Unreal isn’t running, Desktop can import through `UnrealEditor-Cmd` instead. To allow this, turn on Auto-import via UnrealEditor-Cmd when UE is not running in Settings → Unreal. ## Collect and choose instances When you open the Publish tab, Dousen collects the publishable objects in your scene and lists them as instances. Only checked instances are published. If you change the scene, click Reset to collect again. Group by Type only changes how the list is arranged. In Blender, the list is under Refresh Instances in the Dousen sidebar tab. For what each application collects, see What becomes an instance? In Maya and 3ds Max, right-click an instance and choose a profile under Set Import Profile to set how Unreal imports it. The choice overrides the scene’s `import_profile` tag, and (none) clears it. The submenu appears when the project defines import profiles, and never on texture instances, because profiles only apply to meshes and animations. See Interchange. Blender and Houdini have no per-instance control yet. In Maya, + Instance from Selection creates an instance from the selected objects. To change an instance’s type, right-click its row and choose Set Type. Point to each instance to check its name and Unreal destination. If two checked instances would export to the same file, Publish is unavailable until you rename or retag one of them. ## Validate and resolve errors Click Validate to check the checked instances without exporting. Failing and warning rules appear first. Expand a rule to see the affected instance and read the message. Click Select Invalid to select the failing objects in Maya or 3ds Max, or Repair if the validator offers a fix. Validate again after you edit. Click Publish to validate and export in one step. Any error on a checked instance, including a naming or destination error, stops the publish. If only warnings remain, Dousen asks whether to publish anyway. The rules that run, and their severity, come from your project’s configuration, so ask your project admin if a rule seems wrong. Each validation you run from the Publish tab is recorded in the portal’s Validation history under your email address. See Validation history. ## Follow a publish in Publish history Open the Publish history tab in DousenDesktop. Each row shows the asset name and the Unreal project, a status line, and the stages the publish has passed, for example `validated > exported > delivered > imported`. A row appears when DousenDesktop’s relay accepts the export, so its status line starts at Delivered. The chips at the top show which DCCs and Unreal editors are connected. A connected editor doesn’t mean the import succeeded, so check the status line of the row. | Status line | What it means | What to do | |---|---|---| | Delivered - waiting for Unreal import confirmation | DousenDesktop accepted the export. Unreal hasn’t reported the import yet. | Wait for the import result. If nothing changes, check that the Unreal editor for the project is connected. | | Imported and saved in Unreal | Unreal confirmed that it imported the asset and saved the required packages. | Open the asset in Unreal. Submitting in Perforce is a separate step. | | Publish failed - advice | A stage returned a failure. The status line ends with advice for that failure, for example “Fix the export error and publish this instance again.” | Fix the cause, then click Retry publish if the row offers it, or publish again from the DCC. | | Import not confirmed - check Unreal before publishing again | Dousen can’t tell whether the import finished. | The asset may already exist. Inspect the destination in Unreal and fix any partial result before you try again. | The stage list includes `validated` only when validation ran for that publish. A save-triggered publish skips that stage because it doesn’t run the validators. Publish history lists exports from the Publish tab, from Blender’s Publish Checked Instances, and from auto-publish on save. Other exports don’t get a row: the Houdini shelf export tools, Substance Painter’s own export dialog, the the export-only buttons on the Substance Designer Export tab, and the Send to Painter buttons. If a publish never shows up, click Show connection events at the bottom of the tab to see recent relay traffic, or check the Logs tab. ## Recover from a failed publish If a publish fails, Publish history may offer Retry publish, which resends the original export. The button appears only while you’re signed in as the same user and have the same Unreal project selected. When you click it, DousenDesktop checks the exported file first, and the button tells you what it found: | Button text | What to do | |---|---| | Retry started | Wait for the new status line. | | Export file missing | Restore the exported file, or publish again from the DCC. | | Export changed - publish again | The exported file changed after the first publish. Collect, validate, and publish again from the DCC. | | Select the original Unreal project | Select the Unreal project that the publish targeted, then retry. | | Sign in to original session | Sign in as the user and studio that published, or publish again from this session. | | Reconcile in Unreal first | Check the destination in Unreal before you do anything else. | | Retry unavailable | Publish again from the DCC. | Retry doesn’t add or remove meshes in an imported instance. Use Review instance topology for that. ## First-publish checklist - The source is saved and only the instances you want are checked. - The project, task, workspace, and Unreal project are correct. - Validation passes and no destination conflicts remain. - Publish history shows Imported and saved in Unreal. - The assets exist at the Unreal path that your conventions resolve. - The task’s changelist includes the source scene and the exported files. For Painter and Designer publishes, add the exported files yourself. ## Continue the workflow See DCC addons for what each application collects, Asset validation for validator configuration, Perforce for changelist submission, and Unreal Interchange for import profiles and reimport. Previous ← DCC addons Next Unreal Interchange → ## Quick start — Dousen URL: https://dousen.io/docs/quickstart.html Summary: Set up a Dousen project, install DousenDesktop on each artist machine, and publish your first asset to Unreal Engine. Updated October 2026 Describes how to set up Dousen for a studio: get a server, configure a project, set up an artist workstation with DousenDesktop and the Unreal plugin, and run a first test publish. During the free studio beta, cloud self-serve signup is closed and accounts are set up by hand. To get one, request early access. ## Set up the server and project A project admin does these steps once, before the team is onboarded. - Get a server. On Dousen Cloud, request access, and Dousen provisions a studio instance for you. To self-host, get a license token from Dousen, then run the server with Docker Compose as described in Self-hosted install. It listens on port 8080 and binds to `127.0.0.1` by default. To let artists reach it, put a reverse proxy in front of it, or set `DOUSEN_BIND_HOST=0.0.0.0` on a trusted LAN. - Create the project. Sign in to your studio’s `/portal/` as an Admin. On a self-hosted server, that is `https:///portal/` behind your reverse proxy, or `http://:8080/portal/` on a trusted LAN. Open Projects, click Create Project, enter a Project Name, choose a Version Control System, and click Create. - Configure the project. On the project’s Project settings tab, fill in the sections below. Each has its own Update button. Check the message that appears after you click it. Depot Path (Perforce projects), for example `//depot/MyGame/...`. Artists enter the same path in the wizard’s Workspace step, so send it to them before you roll out. - Source Repository (Perforce projects), if source art lives in a separate repository. See Source repositories. - Jira Configuration: the Jira Base URL, Project Key (for example `DOU`), Email and API Token. To move an issue when its changelist is submitted, also set `jira.on_submit_transition` in Pipeline settings. See Transition the issue on submit. - Add naming and validation rules. Define and save one test naming convention. Then set which validators run for each asset type, and their severity, and the pipeline settings for the DCCs you use. - Optional: set up catalog materials. Follow Create the catalog in Unreal, and check that the portal’s Materials tab shows the catalog. - Add a test account. Invite the artist who will run the first test publish. See How artists sign in. - Note the project details. Write down the project name, paths and project UUID, so artists can check their own setup. ## How artists sign in Every artist enters the same address in the wizard’s Server step. How they sign in depends on how your studio runs Dousen. For sessions, tokens and how each method creates users, see User and auth management. | Method | Studio type | How it works | |---|---|---| | Local password | Self-hosted | DousenCore checks the password. In the portal, an admin opens Users, clicks Invite User, enters an Email, Display Name and Role, and clicks Send invite. The invitee gets an email with a link to set a password. If the server can’t send email, the portal says so, and you can use Resend invite later. | | External directory | Self-hosted, with `DOUSEN_AUTH_MODE=ldap` | The studio’s LDAP or Active Directory checks the password. Dousen creates the user on their first sign-in, with a starting role from their directory groups. A role that you set in Dousen is never overwritten. Invite User creates the user in advance with the role you choose. | | Cloud single sign-on | Cloud | The instance has no passwords of its own. Users arrive through a single sign-on exchange from DousenControl. In DousenDesktop, they sign in with their cloud account password, or click Sign in with Browser for an OAuth sign-in with PKCE. A user in more than one studio sees the Choose Studio dialog first. Invite User in the portal sends a team invitation through DousenControl. | ## Set up an artist workstation Set up one test workstation first. It needs the test artist’s account, Jira access, a Perforce login and workspace, a local source root, the DCC executables and the Unreal project. - Install DousenDesktop. The Windows installer (NSIS) includes the app, the DCC addons and the Unreal plugin. DousenDesktop updates itself. On a cloud studio, you can fill in the wizard’s Server step for artists with a configuration bundle, passed with `--config-url` or dropped as a `dousen-config.json` file. The rest of the wizard still runs. See Pre-configure machines. - Run the setup wizard. The first time DousenDesktop starts, it opens a full-window wizard. Click Get Started to begin the six steps, or click I’ll set up later to close the wizard and set up from Settings instead. Every step except the last has a Skip button, and no field is required before you click Next. Enter what you have and finish the rest in Settings later. The last step has Finish instead. | Step | What it asks for | |---|---| | Server | Dousen Cloud or Self-hosted, and the control plane URL or server URL. | | Jira | Your Jira base URL, email and API token. Test Connection checks them. | | Version Control | Perforce Helix Core (with your P4PORT and P4USER, and Sign in to Perforce), or Git / Skip for now. | | Workspace | Perforce only: the depot path, a local root and a workspace name. The wizard checks for an existing mapping, or creates a workspace. | | Unreal Project | The path of your `.uproject` file. The wizard checks for a `Plugins/DousenUE` folder. | | DCC Applications | The DCCs the wizard found on your machine, with a checkbox for each. + Add manually adds one it didn’t find. | Jira: if Test Connection fails, the status line shows the error. Click Skip, and fix the connection later in Settings → Jira. See Jira tasks. - Version Control: if you choose Git / Skip for now, the wizard skips the Workspace step. Changelists, file locks and streams need Perforce. - Workspace: enter the depot path and click Check. If no workspace maps the path, enter a local root and a workspace name, and click Create Workspace. The wizard doesn’t sync the new workspace, so sync it from P4V or UnrealGameSync before you continue. If the Helix command-line client isn’t on your `PATH`, you see “Failed to start p4. Is it installed and on PATH?”. If your project keeps source art in a separate repository, select Source art lives in a separate repository and fill in the fields that appear. See Automatic workspace from the depot path and Source repositories. - Unreal Project: this step doesn’t install the plugin. You do that in step 4. - DCC Applications: the wizard searches the Windows registry, common install folders and your `PATH` for Blender, Maya, 3ds Max (Windows only), Houdini, Substance Painter and Substance Designer. Clear the ones your studio doesn’t use. The wizard doesn’t look for Unreal. - Launch DCCs from DousenDesktop. Start each DCC from the apps bar in DousenDesktop. Desktop starts it with the Dousen addon loaded, and the addon connects to the local bridge on `127.0.0.1:8766`. A shortcut on your desktop starts the plain application without the Dousen panel. To check a DCC’s executable path, open Settings → DCC Apps. See DCC addons. - Add the Unreal Engine plugin. In Settings → Unreal, click Install into .uproject to copy the DousenUE plugin into your project’s `Plugins` folder, or copy the folder yourself. Then add the connection settings to the `[/Script/DousenUE.DousenProjectSettings]` section of `Config/DefaultDousenUE.ini` in your Unreal project. Don’t put them in `DefaultEngine.ini`. INI`[/Script/DousenUE.DousenProjectSettings] ServerScheme=https ServerHost= BridgeRelayHost=localhost BridgeRelayPort=8766 ProjectId=` Set `ProjectId` to the project’s UUID. `BridgeRelayHost` must be `localhost`, `127.0.0.1` or `::1`, because DousenDesktop runs on the same machine as the editor. For every key and the environment variables that override them, see Configure the plugin. ## Verify your first complete publish Run this test on the workstation you just set up, before you onboard anyone else. It goes from a task to an asset in Unreal. For the stages a publish passes through, see Publishing assets. - Open a task. In DousenDesktop’s My tasks tab, click a task to see the issue’s description and details. See Jira tasks. - Check the Perforce connection. The status bar should read `P4: ` or `P4: (classic)`. If it reads `P4: not connected`, see Perforce. - Try a badly named asset. Launch a DCC from DousenDesktop and publish an instance whose name breaks your naming conventions. Depending on your validator settings, Dousen blocks the publish or warns you before anything is published. See Asset validation. - Publish a correctly named asset. Save the source file inside the project’s source root, and open the Dousen panel in the DCC. The panel lists the publishable objects in your scene as instances. Check only the instances you want to publish, click Validate, and fix any errors. Review any warnings, and then click Publish. In Substance Painter, set the Target Unreal mesh before you publish texture sets. For the panel in each DCC, see DCC addons. - Check the asset in Unreal. Start Unreal Editor with the project and the DousenUE plugin enabled. In DousenDesktop, open Publish history and wait for Imported and saved in Unreal. Then find the asset in the Content Browser. If Publish history shows the import as failed or unconfirmed, check the project in Unreal before you publish again. See Recover from a failed publish. After the test, review and submit the task’s changelist as you normally would. You are ready to onboard the team when an artist can select the project, open a task, save a source file under its mapped root, and publish one instance into the expected Unreal folder. Next, read Publishing assets. Before you set up geometry profiles or project import stacks, read Unreal Interchange. Previous ← Overview Next Desktop app → ## Self-hosted install — Dousen URL: https://dousen.io/docs/self-hosted.html Summary: Install and configure Dousen on your own server with Docker, including licensing, directory sign-in, and troubleshooting for self-hosted studios. Updated October 2026 Describes how to run the Dousen server (DousenCore) on your own infrastructure with Docker Compose, including configuration, licensing, directory sign-in, and troubleshooting. One container runs the API and web portal, and one runs MariaDB. DousenDesktop and the Unreal plugin talk to the API over HTTP and JSON on port 8080. Dousen’s cloud control plane, DousenControl, issues your signed license and receives your instance’s license heartbeat. You don’t run it yourself. The deployment bundle in `deploy/self-hosted/` contains `docker-compose.yml`, the `install.sh` helper, an annotated `.env.example`, and `SELF_HOSTING.md` with operational notes. Where those files differ from this page, follow this page. If you don’t have the bundle, email hello@dousen.io. `install.sh` is the fastest way to install. It generates the database and JWT secrets, asks for your license key, Perforce details, and whether to expose Dousen on the local network, writes a `chmod 600` `.env` in `~/.dousen` (or `DOUSEN_INSTALL_DIR`), and starts the stack. At the public-key prompt, enter the path to the PEM file (a leading `~/` works) or paste the whole PEM. Leave it blank to add the key to `.env` later, as described under Install. To review every setting before anything runs, follow the Install steps instead. ## Requirements - A Linux host (Ubuntu 22.04+ or Debian 12+) with Docker 24+, Docker Compose v2, and at least 2 GB RAM (4 GB recommended). - Persistent storage, and an HTTPS hostname for the studio. - A Dousen license: the token and its public key, issued for your studio. Self-serve issuance isn’t live yet, so email hello@dousen.io to get one. Without a license, DousenCore starts locked (see Licensing). - Optionally, a Perforce server, a Jira Cloud site, an LDAP or Active Directory directory, and an SMTP server for invite and password-reset emails. ## Install and verify a studio server - Run the install script or follow the Install steps. Keep the `.env` file private, because it holds the database credentials and secrets. - Start the Compose services and read the logs. The database should initialize, with no JWT secret error and no `Core is locked` license message. - Create the first admin, open `/portal/` at the studio’s HTTPS hostname, and sign in. Create one test project, then invite one test artist. - On an artist workstation, sign in to DousenDesktop against that hostname. Set up the artist’s own Jira and Perforce access in Desktop, which is separate from the server-side integrations. - Install the matching DousenUE plugin, configure the test project, and run a complete test publish. - Before rollout, back up the database, the persistent data, and the deployment configuration. Restore the backup to a test instance, then sign in to the portal and DousenDesktop on it as in steps 3 and 4. The server is ready when portal sign-in, project configuration, artist sign-in, and a saved Unreal import all work through the studio URL. A healthy container doesn’t prove this, because `/health` keeps answering while Core is locked. ## Install Run every `docker compose` command on this page from the directory that holds `docker-compose.yml` and `.env` (`~/.dousen` if you used `install.sh`). - Copy the bundle and create your env file. Copy `deploy/self-hosted/` to the host and copy `.env.example` to `.env`. Every setting on this page goes in this file. If you ran `install.sh`, it already wrote `~/.dousen/.env`, so skip this step. - Fill in the required values. Set the database passwords, `DOUSEN_JWT_SECRET`, and your license key and public key. Put the public key in double quotes, either on several lines or on one line with `\n` between the lines. Replace the placeholder secrets with generated ones: SHELL`openssl rand -hex 32` `DOUSEN_JWT_SECRET` must be at least 32 bytes. If it’s shorter, DousenCore exits at startup with `JWT secret must be at least 32 bytes, got N`. Length is the only check, so the 33-character placeholder in `.env.example` passes. Replace it with the 64-character output of `openssl rand -hex 32`. - Start the stack. SHELL`docker compose up -d` The API container waits until MariaDB reports healthy, runs its database migrations, and starts on port 8080. Migrations run on every start, so there’s no separate migration step. - Check that the server answers. SHELL`curl http://localhost:8080/health` The admin portal is at `http://:8080/portal/`, and `/` and `/portal` both redirect there. Next, create the first admin. ## Create the first admin A new instance has no users, and the portal has no sign-up page, so create the first admin with `dousen-cli`, which is in the container image. Set your license first, because a locked instance refuses portal sign-in. SHELL`docker compose exec dousen-api sh -c 'dousen-cli --database-url "$DOUSEN_DATABASE_URL" \ create-user --email admin@studio.com --display-name "Studio Admin" --role admin \ --password "choose-a-strong-password"'` The command creates the account under a placeholder tenant. DousenCore moves it to your licensed tenant when it starts, so restart the API container afterward: SHELL`docker compose restart dousen-api` Open `/portal/` and sign in with that email and password. Because the password was typed on the command line, change it on your account page (`/portal/account`). From then on, add people with Invite User (see User and auth management). With directory sign-in (`DOUSEN_AUTH_MODE=ldap`), you can skip the command. The first successful sign-in by a member of `DOUSEN_LDAP_ADMIN_GROUP` creates an Admin account, provided that Dousen has a user search base (see Directory sign-in). ## Configuration reference All server settings are environment variables in `.env`. The shipped `docker-compose.yml` passes only the variables listed in the `environment:` block of the `dousen-api` service, so any other variable in `.env` has no effect. The tables below mark the settings that block lacks. To use one, add it in the same form as the existing entries (`VAR: ${VAR:-default}`). ### Required | Variable | Purpose | |---|---| | `MARIADB_ROOT_PASSWORD` | Root password for the bundled MariaDB. | | `MARIADB_USER` / `MARIADB_PASSWORD` | The service account the API uses (default user `dousen`). | | `DOUSEN_JWT_SECRET` | Secret for signing session tokens, at least 32 bytes. See Install. | | `DOUSEN_LICENSE_KEY` | Your license token, pasted exactly as issued. | | `DOUSEN_LICENSE_PUBLIC_KEY_PEM` | The public key issued with the license. DousenCore uses it to verify the license offline. If the value isn’t a valid PEM public key, Core starts locked and logs the reason. See Licensing. | ### Optional | Variable | Purpose | |---|---| | `DOUSEN_CONTROL_PLANE_URL` | Where the license heartbeat goes. The default is `https://control.dousen.io`. Set it to empty to turn the heartbeat off. A heartbeat that fails because of the network is logged and retried, so offline networks work. See Licensing. | | `DOUSEN_P4PORT` / `DOUSEN_P4USER` / `DOUSEN_P4CLIENT` / `DOUSEN_P4PASSWD` | The server’s own Perforce connection. See Perforce for what uses it. Artists' Perforce users are set in DousenDesktop. | | `DOUSEN_WEBHOOK_SECRET` | Shared secret for the Jira webhook at `/webhooks/jira`. | | `DOUSEN_BIND_HOST` / `DOUSEN_REST_PORT` | Where the API port is published on the host. The default is `127.0.0.1:8080`, which is loopback only. Put a reverse proxy in front (recommended, and where you terminate TLS), or set `DOUSEN_BIND_HOST=0.0.0.0` to expose the port directly on a trusted LAN. If artists can’t reach the server, check this first. | | `DOUSEN_VERSION` | Image tag to run. The default is `latest`. Pin a version to control upgrades. | | `RUST_LOG` | Log level. The default is `info`. | | `DOUSEN_SECURE_COOKIES` | Sets the `Secure` flag on session cookies. The default is `true`. Not in the default compose file. If you test over plain HTTP without a reverse proxy, add it and set it to `false`. Otherwise the browser drops the `Secure` cookie, and login appears to succeed but returns to the sign-in page. | | `DOUSEN_CORS_ORIGINS` | Comma-separated allowed origins. The default is same-origin only, which suits the single-container setup. Set it only if you serve the portal UI from a different origin than the API. Not in the default compose file. | ### Email: invites and password resets (SMTP) DousenCore uses SMTP to email invites (Invite User) and password-reset links. The default compose file doesn’t pass these variables through, so add them to the `environment:` block. | Variable | Purpose | |---|---| | `DOUSEN_PUBLIC_URL` | Public base URL used to build the links in emails (`{public_url}/portal/reset-password?token=…`). The default is `http://localhost:8080`. Set it to your real reverse-proxy URL. | | `DOUSEN_SMTP_HOST` | SMTP server. Empty (the default) turns email sending off. | | `DOUSEN_SMTP_PORT` | The default is `587` (STARTTLS). | | `DOUSEN_SMTP_USER` / `DOUSEN_SMTP_PASSWORD` | SMTP login credentials. | | `DOUSEN_SMTP_FROM` | From address. The default is `noreply@dousen.local`. | With `DOUSEN_SMTP_HOST` unset, Invite User still creates the account and Send reset link still creates the reset token, but no email goes out. The portal then shows "… was created, but SMTP isn't configured on this instance — no email was sent." after an invite and "SMTP not configured — no email sent. The link is logged only at debug level (RUST_LOG=info,dousen_api::email=debug)" after a reset. The invite message also says the link is logged only at debug level. A malformed `DOUSEN_SMTP_HOST` logs a warning at startup and behaves the same way. Core logs the link only at the `debug` level. To get it: - Set `RUST_LOG=info,dousen_api::email=debug` in `.env` and run `docker compose up -d`. - Click Resend invite in the user’s row, or Send reset link for an account that already has a password. Then search the log for the `email (SMTP disabled)` line: SHELL`docker compose logs dousen-api | grep "email (SMTP disabled)"` - Give the link to the user yourself. - Set `RUST_LOG` back to `info`, because that log line contains the token. Once SMTP is configured, the same actions send the email over STARTTLS, and the portal reports "Invitation sent to …" or "Reset link sent". ### Directory sign-in (LDAP / Active Directory) By default, users sign in with passwords stored on the instance (`DOUSEN_AUTH_MODE=local`). To use your directory instead, set `DOUSEN_AUTH_MODE=ldap`. DousenCore then creates an account on a user’s first successful sign-in: members of the admin group become Admins and everyone else becomes an Artist. After that, the role you set in Dousen wins (see Which role wins). | Variable | Purpose | |---|---| | `DOUSEN_LDAP_URL` | Directory server, for example `ldaps://ad.studio.lan`. | | `DOUSEN_LDAP_BIND_DN_TEMPLATE` | Template for the bind DN of the signing-in user. For example, `{username}@studio.local` (AD UPN) or `uid={username},ou=people,dc=studio,dc=local` (OpenLDAP). | | `DOUSEN_LDAP_USER_SEARCH_BASE` / `DOUSEN_LDAP_USER_FILTER` | Where and how to look users up, for example the base `OU=Staff,DC=studio,DC=local` and the filter `(sAMAccountName={username})`. If you leave the base unset, Dousen derives it from `DOUSEN_LDAP_BIND_DN_TEMPLATE`: the parent DN of a DN-style template, or `dc=x,dc=y` from `{username}@x.y`. If you leave the filter unset or empty, it uses the first RDN of a DN-style template, such as `(uid={username})`, and otherwise `(sAMAccountName={username})`. At startup, Dousen logs a warning if it can’t derive a base. Without a working base and filter, Dousen can’t read the user’s email or groups: everyone becomes an Artist, the admin group is ignored, and an invited account doesn’t attach to that user’s first sign-in. | | `DOUSEN_LDAP_ADMIN_GROUP` | Directory group (a CN or a full DN) whose members become Dousen admins when their account is first created. | | `DOUSEN_LDAP_START_TLS` | Turns on StartTLS. The default is `false`. Prefer an `ldaps://` URL instead. | Dousen binds as the signing-in user, so you don’t need a service account, and it always rejects empty passwords. If the directory returns no `mail` attribute for a user, the login name becomes the Dousen account identifier. ## Connect DousenDesktop and Unreal Check that `/health` answers before you give DousenDesktop to artists. Then, on each workstation: - Install DousenDesktop and choose Self-hosted on first launch. Onboarding asks whether the studio is Dousen Cloud or Self-hosted. Choose Self-hosted and enter the Server URL: the address your reverse proxy exposes, or, on a trusted LAN, the host’s address on port 8080. Click Test Connection and continue after it shows ✓ Connected. The test only checks `/health`, which also answers while Core is locked, and setup doesn’t require it to pass. Then finish setup. - Sign in. With `DOUSEN_AUTH_MODE=local`, artists sign in with the email and password they set from their invite email (see User and auth management). With `DOUSEN_AUTH_MODE=ldap`, they sign in with their directory credentials. To change the address later, edit the server URL on the Connection tab of DousenDesktop’s Settings dialog. The Unreal plugin has its own server settings in `Config/DefaultDousenUE.ini`. Set `ServerScheme` and `ServerHost` to the same server as the Server URL in Desktop. The plugin takes its DousenCore access token from Desktop’s credential file (`core.credentials.json`, next to `bridge.token`), and uses it only when the server URL in that file matches. Artists open Unreal themselves while DousenDesktop is running and signed in. For `ProjectId`, the bridge port, and environment overrides, see Configure the plugin. The Unreal plugin refuses to contact DousenCore over plain HTTP unless the host is loopback, and its `ServerScheme` defaults to `https`. If you expose the port on a LAN without TLS, the Output Log shows `Refusing to contact DousenCore over cleartext HTTP on a non-loopback host`. Put the instance behind a reverse proxy with TLS and use an `https` address. ## Licensing The license is an Ed25519-signed JWT (`DOUSEN_LICENSE_KEY`) plus the public key issued with it (`DOUSEN_LICENSE_PUBLIC_KEY_PEM`). The token encodes your tier, seat count, features, and expiry. DousenCore verifies it offline against the public key, so it works on an air-gapped network. DousenCore fails closed. Without a valid license it starts locked, and the only bypass is the development setting below. At startup: | License state | Result | Log line | |---|---|---| | No public key | Locked | `DOUSEN_LICENSE_PUBLIC_KEY_PEM not set — Core cannot verify any license and is locked (fail closed)` | | Public key set, but no license key and no saved license | Locked | `DOUSEN_LICENSE_KEY not set and no persisted license found — Core is locked (fail closed)` | | Public key set, but not a valid PEM | Locked | `DOUSEN_LICENSE_PUBLIC_KEY_PEM is not a valid PEM public key (…) — Core cannot verify any license and is locked (fail closed)`, followed by the parse error | | Valid, unexpired license | Starts normally | `license valid`, with the tier, seat count, and days until expiry | | Expired, within the 14-day grace period | Keeps running. Artists aren’t blocked. | `LICENSE EXPIRED — operating in grace period. Renew at https://dousen.io/billing` | | Expired past the grace period, or a token that fails verification | Locked | `license validation failed — Core is locked (fail closed)`, followed by the reason | A locked instance keeps running, but the portal, the `/api/*` endpoints, and the Jira webhook return HTTP 403 with `"code": "unlicensed"` and a message that starts with `Dousen Core is unlicensed:`. Artists can’t sign in or refresh their sessions. `/health` and `/metrics` still answer. The instance can also lock while it’s running: - Expiry: Core checks the expiry locally every hour. When the license passes the end of its grace period, Core locks and logs `license expiry recheck failed: … — Core is now locked`. - Heartbeat: unless `DOUSEN_CONTROL_PLANE_URL` is empty, Core sends the control plane a heartbeat with its user count at startup and then every 24 hours. If the control plane replies with a JSON 403 whose code is `revoked`, `cancelled`, or `suspended`, Core locks and logs `license by control plane: … — Core is now locked`. Any other 403, such as a block page from a proxy or firewall, is logged as a warning and doesn’t lock the instance. Other error responses and network failures are only logged, and Core retries on the next heartbeat. While locked, Core sends a heartbeat every hour. If you fix the cause on the control-plane side, for example by paying or getting the license unsuspended, the instance can unlock within the hour. After a `revoked` or `cancelled` reply, Core remembers the rejection across restarts, so only a newly issued license unlocks it. A heartbeat can also deliver a renewed license, which Core saves and uses on later starts. To turn the heartbeat off, set `DOUSEN_CONTROL_PLANE_URL=` to an empty value in `.env`. With the heartbeat off, a revoked license keeps working until the license token expires and the 14-day grace period ends. For local development only, `DOUSEN_DEV_UNLICENSED=true` turns on every feature with unlimited seats and no license. Core logs `DOUSEN_DEV_UNLICENSED=true — running with an all-features, unlimited-seat license` at startup. Not in the default compose file. Never set it in a production configuration. The admin portal doesn’t show license or grace-period status. To get warning before the grace period ends, watch `docker compose logs dousen-api` for `license valid`, `LICENSE EXPIRED`, and `Core is locked` or `Core is now locked`, or have your log shipper alert on them. To renew, replace `DOUSEN_LICENSE_KEY` in `.env` with the renewed token and run `docker compose up -d`. ## Operational notes - Backups: the database is in the `dousen-mariadb` Docker volume. `docker volume ls` lists it as `_dousen-mariadb`, where the project name defaults to the name of the install directory. Include the volume in your backup routine. A logical dump looks like this: SHELL`docker exec dousen-mariadb sh -c \ 'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" dousen' \ > dousen-backup-$(date +%Y%m%d).sql` The single quotes make the container’s shell expand `MARIADB_ROOT_PASSWORD`, which exists only inside the container. Back up `.env` too, because it holds your license key and secrets, and store it outside the Docker volume. - Upgrades: change `DOUSEN_VERSION`, then run `docker compose pull && docker compose up -d`. Migrations run on start. If you later roll back to a version older than migration 0032, deactivated accounts can sign in again. - Perforce in Docker: the compose file includes a commented-out `p4d` service for a self-contained evaluation stack. - Kubernetes: Docker Compose is the supported path for self-hosted studios. The Helm chart in `infra/helm/dousencore/` uses the same environment variables but is built for the managed GKE deployment that DousenControl provisions (Cloud SQL, Workload Identity, and a cert-manager ingress). To use it on another cluster, set `mariadb.enabled: true` and replace the ingress and Cloud SQL values instead of running `helm install` unmodified. ## Troubleshooting | Symptom | Check | |---|---| | The log shows `Core is locked (fail closed)` about a missing license key or public key | Set `DOUSEN_LICENSE_KEY` and `DOUSEN_LICENSE_PUBLIC_KEY_PEM` in `.env` and restart. For local development only, `DOUSEN_DEV_UNLICENSED=true` bypasses the check. | | Requests return 403 with `"code": "unlicensed"`, but the container is healthy | Core is locked. Read the reason after `Dousen Core is unlicensed:` in the response and the matching `locked` line in `docker compose logs dousen-api`. See Licensing. | | The API container restarts repeatedly and the log shows `JWT secret must be at least 32 bytes` | Set `DOUSEN_JWT_SECRET` to a value of at least 32 bytes, for example the output of `openssl rand -hex 32`. | | Requests return 403 and the log shows `DOUSEN_LICENSE_PUBLIC_KEY_PEM is not a valid PEM public key` | Core is locked because it can’t read the key. Paste the key again exactly as issued, inside double quotes. See Install. | | API container won’t come up, or database connection errors | Run `docker compose ps`. The `mariadb` service should show `healthy` before `dousen-api` starts against it. | | Login appears to succeed, then returns to the login page | You’re testing over plain HTTP without a reverse proxy, and `DOUSEN_SECURE_COOKIES` defaults to `true`, so the browser drops the `Secure` cookie. Add the variable to the compose file’s `environment:` block and set it to `false` for local testing, or put TLS in front of the server. | | DousenDesktop or the Unreal plugin can’t reach the server | Check that port 8080 (or your reverse proxy’s port) is reachable from the workstation and isn’t blocked by the host firewall. Without a proxy, check that `DOUSEN_BIND_HOST` isn’t still loopback-only. The Unreal plugin also needs an `https` address for any host that isn’t loopback. | | Invite or reset emails never arrive | Check the SMTP settings under Email, and read `docker compose logs dousen-api` for a send failure. | | You need the current logs | Run `docker compose logs -f dousen-api`. | Previous ← User and auth management Next Tools and plugins → ## Settings reference — Dousen URL: https://dousen.io/docs/settings.html Summary: Settings reference for the Dousen desktop app, DCC addons, and project configuration. Updated October 2026 Describes the project settings that a project admin edits in the Dousen web portal, how they reach the DCC addons, and the separate settings that DousenDesktop keeps on each workstation. Project settings control the pipeline behavior that every artist on a project shares. They live in the web portal at `/portal/`, and only admins can edit them. DousenDesktop reads what the portal publishes. Its own settings apply to one workstation. ## Change a project setting and verify it - Sign in to the portal as an Admin and open Projects → your project → Pipeline settings. Check the project name before you change shared defaults. - Copy the current YAML so you can roll back. - Change one group at a time. Use the Form tab for the fields it shows, and the Raw YAML tab for a missing DCC block or a key the form doesn’t show. For example, to triangulate Maya exports, set `export_presets.maya.triangulate` to `true`. - Click Save (Form tab) or Save raw YAML (Raw YAML tab). If the editor shows a YAML error, fix it and save again. Save raw YAML replaces the whole document, so keep the blocks you aren’t changing. Reopen the editor and check the saved value. - Relaunch the test DCC, or wait up to 5 minutes for the addons' cached settings to expire. Startup scripts and the OCIO path need a new launch. See How changes reach a running DCC. - Publish a small test instance and check the behavior you changed. For the Maya example, open the exported FBX and confirm that the mesh is triangulated. - If the test breaks, restore the YAML you saved and check it again before you ask the team to refresh. You set up material catalogs in Unreal instead. Author the Data Asset and configure the plugin, then check the portal’s read-only Materials tab. See Materials and textures. ## Where settings live Each project has several YAML documents and a few single-value fields, all edited from the project view in the portal. | Setting | What it controls | |---|---| | Pipeline settings | Export and import behavior, texture rules, custom validator paths, OCIO, and the Jira transition on submit. This page covers them. | | Naming conventions | Asset naming rules. See Naming conventions. | | Validators | Pre-export and admin asset checks. See Asset validation. | | Jira config | Base URL, project key, account email, and a write-only API Token field for server-side actions such as the Jira transition on submit. Leave the token blank to keep the saved one, or enter a new value to rotate it. See Jira. | | Perforce depot path | The depot path that onboarding uses to create artist workspaces. See Perforce. | ## Workstation settings in DousenDesktop DousenDesktop keeps a few local settings for each workstation in a `config.ini` file (see Where logs and config live for its location). It reads them at launch and never sends them to DousenCore, so two artists on the same project can have different DCC launch arguments or Jira accounts. You edit them in DousenDesktop’s Settings dialog. | Local setting | Where you edit it | What it controls | |---|---|---| | Launch Arguments and Environment Variables | Settings → DCC Apps, for each app entry | Extra command-line arguments and environment variables for launching one DCC on this machine. See Loading studio tools. | | Jira base URL and email (`jira_base_url`, `jira_email`) | Settings → Jira | This machine’s Jira connection, used to fetch tasks directly from Jira. The API token is stored separately, in obfuscated form. See Jira tasks. | | Headless import (`ue_auto_import_when_closed`, `ue_editor_cmd_path`) | Settings → Unreal, in the Headless Import (UE Closed) group | Whether DousenDesktop imports assets with `UnrealEditor-Cmd` when the Unreal editor isn’t running (the Auto-import via UnrealEditor-Cmd when UE is not running checkbox), and the path to that executable. See Unreal Engine. | | Cloud storage mounts (`gdrive_mount_path`, `onedrive_mount_path`) | Settings → Connection, in the Cloud Storage Mounts group | Local mount points for source assets stored on Google Drive or OneDrive instead of Perforce. | | Perforce connection (`default_p4_port`, `default_p4_user`, `default_p4_workspace`, `default_p4_local_root`) | Setup wizard | The Perforce server, user, workspace, and local root that this machine uses. See Perforce. | ## Pipeline settings Pipeline settings are one YAML document per project. Dousen ignores keys it doesn’t recognize, so you can keep studio-specific notes in the same document. | Key | Meaning | |---|---| | `export_presets..` | Per-DCC export defaults. The supported DCCs are `blender`, `maya`, `3dsmax`, `houdini`, `substance_painter`, and `substance_designer`. | | `texture.allowed_formats` | The texture file formats that artists may export. `tga` is the recommended default. `png`, `exr`, and `tif` are also accepted. See Texture rules. | | `validators.extra_paths` | Folders to load custom validators from. Each entry can be a Perforce path (`//depot/...`), a path relative to the source root, or an absolute path. See Asset validation. | | `app_paths..startup_scripts` | Studio scripts that run after Dousen’s own DCC initialization, so you can load your existing pipeline tools without disturbing the addon. See Loading studio tools. | | `jira.on_submit_transition` | The Jira transition that Dousen applies when a linked changelist is submitted. The match isn’t case-sensitive. Leave it blank to turn the feature off. See Jira tasks and Perforce. | | `ocio.config_path` | A shared OCIO config for every DCC. If it’s blank, each DCC keeps its own default color setup. | ### Export presets Presets are keyed by DCC, then by setting name. Each addon reads only its own DCC’s block and applies the keys below as native export options. It skips any other key without an error, so `up_axis` has an effect only under `3dsmax`. | DCC | Keys under `export_presets.` | Applied as | |---|---|---| | `blender` | `apply_modifiers`, `embed_textures`, `use_armature_deform_only`, `bake_anim`, `bake_anim_use_all_bones`, `bake_anim_step`, `axis_forward`, `axis_up` | Keyword arguments to `bpy.ops.export_scene.fbx()`. | | `maya` | `fbx_version`, `embed_textures`, `smoothing_groups`, `hard_edges`, `tangents`, `smooth_mesh`, `triangulate` | `FBXExport*` MEL commands that run before `FBXExport`. | | `3dsmax` | `fbx_version`, `smoothing_groups`, `tangents`, `triangulate`, `embed_textures`, `preserve_instances`, `up_axis` | `FBXExporterSetParam` calls through `pymxs`. | | `houdini` | `alembic_format`, `flatten_hierarchy`, `save_attributes` | Parameters on the Alembic ROP node (`format`, `flatten`, `savealiases`). | | `substance_painter` | `format` | The file format of the exported textures. The default is `tga`. | | `substance_designer` | `format` | The file format of the exported textures. The default is `tga`, including for Send to Unreal. | - Blender’s FBX exporter has no version option, so the `blender` block ignores `fbx_version`. Blender also always exports baked animation without curve simplification, whatever the preset says. - Maya always exports without the constant key reducer, so held keys and hand-shaped tangents survive. No preset key changes this, and `apply_modifiers` has no effect in Maya. In the Form tab, these keys have a dropdown with a fixed set of values. The API doesn’t validate them, so the Raw YAML tab or a direct `PUT` accepts any string. - `fbx_version` (Maya and 3ds Max): `FBX202000`, `FBX201900`, `FBX201800` - `axis_forward`: `-Z`, `Z`, `-Y`, `Y`, `-X`, `X` - `axis_up`: `Y`, `Z`, `X`, `-Y`, `-Z`, `-X` - `up_axis` (3ds Max): `Y`, `Z` - `alembic_format`: `Ogawa`, `HDF5` - `format` (Substance): `tga`, `png`, `exr`, `tif`, `jpg` ### Texture rules Substance Painter and Substance Designer refuse to export a texture whose format isn’t in `texture.allowed_formats` when Dousen starts the export, for example with Publish or Export Textures. The reason appears in the Publish results, and on the Designer Export tab. If you export with Painter’s own export command, the addon prints a console warning for each file whose extension isn’t on the list but doesn’t block the export. Use TGA for source textures. The Substance Painter addon exports TGA, and so does Export Baked Textures in Substance Designer. The source format never ships, because Unreal recompresses every texture to a GPU block format (BC or ASTC) when it cooks. TGA has no color-management metadata, so data maps such as normal, roughness, metallic, and masks stay linear. Tools handle PNG’s optional gamma, sRGB, and ICC chunks inconsistently, which can gamma-correct a linear map by mistake, and PNG leaves RGB values under fully transparent pixels undefined. For linear data above 8 bits, such as heightmaps and HDR, use `exr` or 16-bit `tif`, because 8-bit linear data bands. On import, the Dousen plugin sets each map’s sRGB flag by channel, whatever the format: BaseColor and Emissive are sRGB, and Normal, Roughness, Metallic, AO, ARM, Mask, Height, and Opacity are linear. So the PNG problems matter mainly when you exchange files with other tools. PNG files are smaller in source control. The texture size limits `texture.max_resolution` and `texture.resolution_power_of_2` are validator rules that you set in the Validators tab. See Asset validation. ### Example YAML`export_presets: blender: axis_forward: -Z axis_up: Y maya: fbx_version: FBX201900 smoothing_groups: true 3dsmax: up_axis: Z houdini: alembic_format: Ogawa texture: allowed_formats: [tga, png, exr, tif] validators: extra_paths: - //depot/pipeline/dousen/validators - ./tools/validators jira: on_submit_transition: In Review ocio: config_path: //depot/color/aces/config.ocio ` ## Who can view and edit Any signed-in member of the project’s tenant can read the current YAML, and so can the DCC addons, which use the same server-issued token. Only admins can save, in the portal or through the API: `PUT /api/projects/:id/settings` returns `403 Forbidden` for any other role. ## Editing in the portal The project’s Pipeline settings page has two tabs over the same document: - Form shows typed fields: dropdowns for the fixed-value keys listed under Export presets, checkboxes for booleans, and comma-separated or one-per-line lists for `texture.allowed_formats` and `validators.extra_paths`. It builds a section for each DCC block (export presets and startup scripts) that already exists in the YAML. Save merges the fields into the existing document, so keys the form doesn’t show, such as studio comments or experimental settings, stay as they were. - Raw YAML edits the full document. Save raw YAML replaces the whole document with the editor’s content. Use it to add or restructure keys that the form doesn’t show. Both tabs reject text that doesn’t parse as YAML and show an inline error. ## API endpoint | Method | Endpoint | |---|---| | GET | /api/projects/:id/settings | | PUT | /api/projects/:id/settings | The body is the settings YAML. If a project has never saved custom settings, `GET` returns the built-in defaults instead of an error. If the body doesn’t parse as YAML, `PUT` returns `400 Bad Request` and the previous settings stay in place. ### How changes reach a running DCC - Export presets, allowed texture formats, and custom validator paths: each DCC addon caches them in memory for 5 minutes, like the naming conventions. A change reaches an artist who’s already working within about 5 minutes, without a relaunch. - `ocio.config_path`: applied when the DCC starts, so a change takes effect the next time the artist launches that DCC. - `app_paths..startup_scripts`: DousenDesktop resolves it once, when it launches the DCC, so a change also takes effect on the next launch. See Loading studio tools. - `jira.on_submit_transition`: read from the database on every changelist submit, without caching, so a change applies to the next submit. ## Asset versions Dousen keeps an immutable version of each published asset. A version records the Perforce changelist, the Jira key, the publisher, and the version’s file representations and dependencies. The history is read-only, is available through the API, and has nothing to configure. Previous ← Materials and textures Next Loading studio tools → ## Source repositories — Dousen URL: https://dousen.io/docs/source-repository.html Summary: How to connect a project to a separate Perforce repository for DCC source art, and how syncing, changelists and reimport work with it. Updated October 2026 · Project admins and artists Describes how to connect a project to a separate Perforce repository for DCC source art, and how artists sync, publish and submit when a project uses one. Some studios keep DCC source files (Maya, Blender, 3ds Max, Houdini and Substance files) in a large Perforce repository that the Unreal project doesn’t map, sometimes on a different server. If you bind the Dousen project to that repository, artists sync only the files they work on, and nothing syncs in bulk. If your source files are in the Unreal repository, leave Mode at Same as UE repo, the default. ## Set up and test a separate source repository - In the web portal, sign in as an Admin, click Projects, select your project, and click Project settings. In the Source Repository section (shown only for Perforce projects), set Mode to Separate repo. - Enter Source P4PORT and Source Depot Root. Optionally enter a Stream. Choose FBX Location and Client View Mode. If FBX Location is In the UE repo, also enter UE FBX Root. The settings reference describes each field. - Click Update. - On one artist workstation, create the source workspace and sign in to the source server. - In a DCC, click Set Up Asset to create a test asset. In P4V, check that the file’s folder is mapped in the source workspace and that the file is in the source changelist. - Publish the asset. Check that the FBX and its sidecar are where FBX Location says, and that Unreal imported and saved the asset. On a second workstation, try Open in DCC and Reimport (sync source) from the Unreal Content Browser. - Review the source and Unreal changelists separately, then submit. If only one submit succeeds, see Changelists and the Jira transition. Setup works when both workspaces contain the test task’s files, the source file opens in the DCC, and the publish saves an Unreal asset without syncing the whole art depot. ## Source repository settings Set these fields in the Source Repository section of Project settings in the portal, or send a `source_repo` object in `PUT /api/projects/:id`. The table lists them in the portal’s order. | Field | Meaning | |---|---| | Mode | `same` (Same as UE repo, the default) or `separate` (Separate repo). | | Source P4PORT | The source repository’s Perforce server. Required in separate mode. It can be a different server than the one the Unreal project uses. | | Source Depot Root | For example, `//art-depot/HeroGame/...`. Required in separate mode. Must start with `//`. | | Stream (optional) | The stream path, if the source depot is a stream. | | FBX Location | `source` (In the source repo, next to the scene, the default) writes the exported FBX next to the DCC scene in the source repository. `ue` (In the UE repo) writes it to the Unreal repository under UE FBX Root. | | UE FBX Root | Required when FBX Location is In the UE repo. Must start with `//`. | | Client View Mode | `narrow` (Narrow (widened per folder on demand), the default) or `full` (Full (whole depot; required for streams)). See Narrow and full client views. | | Sync the whole scene folder | Off by default. When on, opening a scene syncs its whole folder instead of only the scene and its manifest. This works around the texture dependency gap in Limitations. | A project that never sets these fields uses `mode: same`. Only an Admin can change them. ## Create the source workspace (artist, once) Each artist creates a second Perforce workspace for the source repository, in an optional section of the Workspace step of the DousenDesktop setup wizard. The wizard can’t read the project’s mode from DousenCore before you sign in, so you enter the second server’s details yourself. After you sign in, the Source Repository group of the Edit Project dialog (Settings → Projects, select the project, click Edit) shows the project’s settings from the portal. - In the Workspace step, select Source art lives in a separate repository. - Enter P4PORT, DEPOT ROOT, P4 USER and LOCAL ROOT. If CLIENT NAME is empty when you choose LOCAL ROOT with Browse, Desktop fills it in as `__src`. If you click Re-run Setup on the sign-in screen after you’ve used a separate-mode project in the same Desktop session, P4PORT, DEPOT ROOT and the full-view checkbox start with that project’s values. On first run they’re empty. - Optionally, select Sync the entire source depot (not narrow) — classic depots only. - Click Create Source Workspace. Desktop then does the following: - Checks your login on the source server (`p4 -p -u login -s`). If you need to sign in, Desktop asks for your password and runs `p4 login` for that server and user. The password goes through standard input and isn’t saved. Desktop shows a connection or character-set error as it is, without a password prompt. If you cancel, nothing changes. For SSO or MFA, sign in with P4V and try again. - Detects streams (`p4 streams`), as it does for the Unreal workspace. A stream depot gets a `Stream:` client spec with a full view, and a classic depot gets a classic client spec. - Checks the workspace name (`p4 clients -e `). If the workspace exists, Desktop asks before it overwrites its Root and View. If you click No, nothing changes. - Creates the workspace (`p4 client -i`) with the options `noallwrite noclobber`, so the `p4 sync` that runs on `dcc.open` and on Unreal reimport can’t overwrite local edits that aren’t opened. It syncs no files, so the workspace stays empty until you open or create an asset. You can sign in to either server at any time with Sign in to Perforce or Sign in to source Perforce in the setup wizard, or with Sign in to source Perforce in the Source Repository group of the Edit Project dialog. ## Narrow and full client views Perforce writes a file to disk only when you sync it. Client View Mode sets what the workspace maps. - Narrow (default, classic depots only). The View starts with a single placeholder line that maps no real files. When you open or create an asset, Dousen adds a View line for that asset’s folder. If someone runs Get Latest on the workspace root in P4V, nothing is mapped, so nothing downloads. - Full (required for streams, optional for classic depots). The View maps the whole source depot, and Dousen still syncs file by file on demand. A stream workspace can’t have a custom View, so a stream depot always uses Full, and the setup wizard shows this warning: "This depot is a Perforce stream — its client always maps the full view. Do not run "Get Latest" on this workspace root; only open assets are synced on demand." The same advice applies to a classic workspace with a full view. ## FBX location - `source` (default) writes the FBX next to the DCC scene. Teammates get the imported `.uasset` through the Unreal project, so they don’t need the FBX. To reimport, you need the FBX and its `.dousen_meta.json` sidecar, and Reimport (sync source) in the Unreal Content Browser syncs both. - `ue` writes the FBX under UE FBX Root in the Unreal repository, so it syncs with everyone’s normal Unreal workspace sync. Use it if teammates or import tools expect the FBX next to or under the Unreal content. ## When Dousen syncs files DousenDesktop syncs files in three cases: - You open a scene in a DCC, with Open in DCC from the task panel or the Unreal Content Browser. Dousen syncs the scene and the files in its `sync_manifest`, which the DCC collects at export time. If Sync the whole scene folder is on, it syncs the scene’s folder too. In narrow mode, it first widens the View for any unmapped folder. - You create a new asset. Dousen maps the new file’s folder before the addon runs `p4 add`. See New assets. - You use Reimport (sync source) in Unreal. Dousen syncs one FBX and its sidecar, and nothing else. See Reimport from Unreal. ## New assets On the New Asset tab of a DCC panel, click Set Up Asset to create a convention-named scene. The addon then: - Resolves the scene path under the source workspace from the project’s naming conventions. It maps `/Game` paths the same way as Unreal import paths. - Calls the bridge operation `source/ensure-mapped` on that path, so the file’s folder is mapped even in narrow mode. `p4 add` has no effect on an unmapped path. If Desktop is an older build without this operation, or the bridge is unreachable, the addon carries on as if there were nothing to map. - Runs `p4 add` on the file, in the changelist of the workspace that owns the path, so a scene in the source repository goes into the source changelist. The exported FBX goes where FBX Location says. Desktop passes that location to the DCC in `DOUSEN_FBX_ROOT` when it launches the DCC. ## Changelists and the Jira transition For each task, a project with a separate source repository opens one changelist in the source repository and one in the Unreal repository. DousenCore tracks each by server, user and workspace. Dousen submits the source changelist first. The Jira issue moves after the last of a task’s changelists is submitted. Before it moves the issue, DousenCore checks for another pending, non-empty changelist for the same task, project and user. The check locks the rows it reads, so two simultaneous submits can’t both skip the transition. An artist often changes files in only one repository. `p4 submit` fails on an empty changelist, and an empty pending one would block the Jira transition, so Desktop checks each changelist for opened files before it submits: - It deletes an empty changelist in Perforce (`p4 change -d`) and reports it to Core as abandoned (`abandoned: true`). Core marks it reverted, so it no longer blocks the transition. Abandoning a changelist doesn’t move the issue by itself. - It submits only the non-empty changelists, source first. - If every changelist is empty, it shows "Nothing to submit: every changelist for this task is empty." - If it can’t look up the source changelist, it cancels the whole submit with "Could not look up the source-repository changelist; nothing was submitted." It never submits only the Unreal half. Submits to two servers aren’t atomic. If the source submit fails, Dousen doesn’t submit the Unreal changelist. If the Unreal submit fails after the source submit succeeded, the Jira issue doesn’t move until you submit the Unreal changelist again. ## Reimport from Unreal In the Unreal Content Browser, right-click an asset that Dousen imported from a project with a separate source repository and choose Reimport (sync source), followed by the asset name. The entry appears when the asset has `Dousen.PublishedDepotPath` metadata, which Dousen adds at import time whatever `fbx_location` is. The command syncs only the FBX and its `.dousen_meta.json` sidecar, through the bridge operation `source/sync`, and then reimports from the synced local path. It doesn’t sync the DCC scene, because the reimport doesn’t need it. ## Safeguards - Local edits aren’t overwritten. Before any on-demand sync, Dousen looks for files that differ from your revision but aren’t opened for edit (`p4 diff -se`). It refuses to sync them and shows "local file has unsubmitted edits (not checked out); check it out or revert before syncing". A workspace that the wizard’s source step creates uses `noallwrite noclobber`. The Unreal workspace that the wizard created earlier still uses `allwrite clobber`, so the diff check is the only protection there. - Mapping is checked in both view modes. Dousen runs `p4 where` even in `full` view mode, and widens the View if the path isn’t mapped. It rejects a depot path that isn’t under the configured depot root. The comparison respects folder boundaries (`//a/art` doesn’t match `//a/artwork`) and ignores case on Windows. Edits to one workspace’s client spec run one at a time. - Credentials. Dousen doesn’t pass the ambient `P4PASSWD` to a server whose `P4PORT` differs from the ambient one, so the password can’t reach the source server or override that server’s login ticket. - Bridge timeouts. The Unreal plugin gives `source/sync` and `source/ensure-mapped` a 120-second timeout on their own worker, so a slow sync on a remote server doesn’t hit the 15-second default or block other calls. In a DCC, the mapping check blocks the UI for at most 8 seconds. If it times out, the addon carries on. ## Limitations - Texture dependencies aren’t synced. No addon adds texture files to the `sync_manifest`. Maya adds referenced scenes, Blender adds linked libraries, and 3ds Max adds XRef scenes. Houdini and the Substance addons add nothing. As a workaround, turn on Sync the whole scene folder, which syncs everything under the scene’s depot folder, including files you don’t need. - A stale changelist on the other server can defer the Jira transition. DousenCore counts any other pending changelist for the same task and user on the other server, even one left over from an old workspace. While one exists, Core defers the transition. You can move the issue in Jira yourself. - No tool moves existing assets to a new source repository. If you switch a project from same mode to separate mode after assets exist, those assets keep the source repository role `ue`, because their files are in the Unreal repository. - Older DCC addon builds put the scene in the Unreal changelist. Separate mode needs a Desktop and addon build that routes the scene through the source workspace. An older addon checks out and adds the scene in the Unreal workspace. ## Troubleshooting "Source Perforce login check failed for as " Perforce tickets are per server, so a ticket for the Unreal project’s P4PORT doesn’t sign you in to a different source P4PORT. Sign in to each server separately, with Desktop, `p4 login` or P4V. The setup wizard and the Sign in to source Perforce button in the Edit Project dialog both report this error. A new asset’s file doesn’t appear in `p4 opened` In narrow mode, a folder where you’ve never opened or created an asset isn’t mapped, and `p4 add` has no effect on an unmapped path. Dousen normally maps the folder first. If it didn’t, for example because Desktop is an older build or the bridge was unreachable, check the binding in the Source Repository group of the Edit Project dialog (Settings → Projects). You can also widen the View yourself: run `p4 client -o`, add a View line for the folder, and run `p4 client -i`. "Do not run Get Latest on this workspace root" If you run Get Latest or `p4 sync //depot/...` on the workspace root, Perforce downloads the entire source depot. This applies to every stream workspace, and to a narrow workspace whose View someone widened to the root by hand. Sync only specific files, or let Dousen sync them on demand. Reimport (sync source) fails or isn’t in the menu The entry appears only on an asset with `Dousen.PublishedDepotPath` metadata, so the asset must have been published from a project with a separate source repository after this feature was released. If the command fails, Unreal shows a notification with the bridge error: an unmapped path, a Perforce login problem, or a missing sidecar. Check the Desktop bridge log, and make sure your tickets for both servers are current. Previous ← Perforce Next Unreal Engine → ## Loading studio tools — Dousen URL: https://dousen.io/docs/studio-tools.html Summary: Load your studio's own tools and validators into the Dousen DCC addons. Updated October 2026 Describes how to load your studio’s own DCC tools alongside the Dousen addon, with startup scripts for the whole project or launch options for one machine. Tools you already load, such as menus, shelves, exporters, and render presets, keep working when you launch a DCC from DousenDesktop. Dousen adds its addon to each application’s search paths without replacing them. ## Install a startup script for the team - Add the script to your studio’s pipeline repository and submit it. Test it in the DCC version your artists use before you add it to a shared launch. - In the portal, open the project’s Pipeline settings and add the script’s path under `app_paths..startup_scripts`, using one of the path forms below. Use the DCC’s key, such as `maya` or `blender`. - Check that the test workstation can read the script through its source root or Perforce workspace. - Save the document. Close the test DCC and launch it again from DousenDesktop. DousenDesktop reads the script list at launch, so a DCC that is already open doesn’t get the new script. - Check that both your tool and the Dousen panel load. If they don’t, see When a script doesn’t load. - To remove the script, delete its path, save, and relaunch the DCC. Custom validator paths are a separate setting and aren’t affected. ## Startup scripts The `app_paths..startup_scripts` key in pipeline settings lists Python files for each DCC. Dousen runs them inside the application at every launch, for every artist, so you don’t install anything on individual machines. YAML`app_paths: maya: startup_scripts: - //depot/pipeline/maya/studio_menu.py - pipeline/maya/shelf_tools.py # relative to the project source root blender: startup_scripts: - C:\StudioTools\blender\init_presets.py houdini: startup_scripts: - //depot/pipeline/houdini/studio_shelf.py` Startup scripts run like this: - Inside the DCC’s own Python interpreter, so `import maya.cmds`, `import bpy`, and `import hou` work as they do in the application’s script editor. - After Dousen’s addon has initialized, so the bridge, the task context, and the Dousen panels are available. - In list order, from top to bottom. - If a script raises an error, Dousen logs it and runs the next script. The artist isn’t blocked. ### Path forms | Form | Example | Notes | |---|---|---| | Perforce depot | `//depot/pipeline/maya/menu.py` | Resolved through the artist’s workspace mapping (`p4 where`). The file must already be synced. Dousen syncs custom validator paths automatically before each discovery pass, but it doesn’t sync startup script paths. | | Relative | `pipeline/maya/menu.py` | Joined to the project’s source root. | | Absolute | `C:\StudioTools\maya\menu.py` | For tools in a workstation image or on a network share. Write shares with backslashes (`\\studio-nas\tools\menu.py`), because Dousen reads any path that starts with `//` as a Perforce depot path. | Keep startup scripts and custom validators in Perforce (a `//depot/...` path). Artists get updates when they sync, and the scripts are versioned with the pipeline. Python only. Dousen runs each entry as Python source. To run MEL or MAXScript, call it from Python with `maya.mel.eval(...)` in Maya or `pymxs.runtime.execute(...)` in 3ds Max. ### Environment variables for startup scripts Dousen sets these variables when it launches the DCC, so your scripts can read the project and task: | Variable | Meaning | |---|---| | `DOUSEN_PROJECT_ID` | The ID (UUID) of the active Dousen project. | | `DOUSEN_SOURCE_ROOT` | The project’s source root on this machine. | | `DOUSEN_CORE_URL` | The base URL of the Dousen server. | | `DOUSEN_TASK_ID` / `DOUSEN_CHANGELIST_ID` | The task and changelist that were active at launch, if the artist had one selected. `DOUSEN_TASK_ID` is Jira’s numeric issue id, not the key such as `DOU-142`. | | `DOUSEN_TASK_TITLE` | The title of the task that was active at launch, if the artist had one selected. | | `P4PORT` / `P4USER` / `P4CLIENT` | The Perforce server, user and workspace for the project’s source files. If the project uses a separate source repository, these are the source repository’s values (see Source repositories), so a `p4` command in a script targets that server. Dousen sets each variable only when it has a value. Otherwise your machine’s own Perforce settings apply. | | `DOUSEN_P4_ROUTES` | A JSON list with one entry for each repository role, `ue` and `source`. Each entry has `role`, `port`, `user`, `client`, `local_root` and `depot_root`. Use it to find the server and workspace for a path when the project has a separate source repository. | | `DOUSEN_FBX_ROOT` | The local folder where Dousen writes exported FBX files. It is the project’s source root, unless the project’s FBX location is In the UE repo. Then it is the matching folder in the Unreal workspace. | | `DOUSEN_OPEN_FILE` | The file being opened, when the DCC was launched with Open in DCC. | | `DOUSEN_BRIDGE_PORT` | The port of the local bridge relay. See Bridge API if your tool needs to publish or subscribe. | | `DOUSEN_HOME` / `DOUSEN_PYTHON_PATH` | The DousenDesktop install root and the path of its bundled Python package. | | `DOUSEN_ADDONS_PATH` | The folder of the Dousen addon for the DCC you launched, `dousen/addons/` inside `DOUSEN_PYTHON_PATH`. Every launch sets it. | | `DOUSEN_CREDENTIAL_FILE` / `DOUSEN_CREDENTIAL_ID` | The path of a credential file that DousenDesktop keeps updated with the signed-in artist’s access token, and the ID of that credential. Dousen’s DCC clients read the token from this file for each request, so it stays valid after DousenDesktop refreshes it. | | `DOUSEN_TOKEN` | Set only when DousenDesktop has no credential file for the session. It holds a fixed token that isn’t refreshed. A normal signed-in session sets the two credential variables instead. | To call DousenCore’s REST API from a script without asking the artist to sign in again, for example `GET /api/projects/:id/settings`, read the current token for each request: PYTHON`import os from dousen.credentials import credential_state state = credential_state(os.environ["DOUSEN_CORE_URL"]) headers = {"Authorization": f"Bearer {state.token}"} # state.token is "" if no valid token is available` PYTHON`# //depot/pipeline/maya/studio_menu.py — runs inside Maya's Python import os import maya.cmds as cmds cmds.loadPlugin("studioTools", quiet=True) task = os.environ.get("DOUSEN_TASK_ID") if task: print(f"[studio] building menu for task {task}")` ## Existing search paths If your pipeline sets the DCCs’ standard environment variables, for example from a studio launcher, a machine image, or artist profiles, Dousen keeps your values and adds its addon directory: | DCC | What Dousen changes | |---|---| | Maya | Adds its addon directory to `PYTHONPATH` and `MAYA_SCRIPT_PATH`. | | 3ds Max | Appends to `ADSK_3DSMAX_STARTUPSCRIPTS_ADDON_DIR`. | | Houdini | Appends the addon directory and the `&` marker to `HOUDINI_PATH`, so Houdini’s default paths still load. | | Substance Painter | Appends to `SUBSTANCE_PAINTER_PLUGINS_PATH`. | | Substance Designer | Appends to `SD_PLUGINS_PATH`. | | Blender | No search-path changes. Dousen starts itself with a `--python` argument, so your Blender addon setup is untouched. | Dousen adds its Python package to `sys.path` after the DCC’s own paths, so it can’t shadow the DCC’s standard library. For Maya and Blender, Dousen also removes an inherited `PYTHONHOME` so that the DCC uses its own Python. ## Per-machine launch arguments and environment variables For changes that apply to one machine, such as a local sandbox, a farm node, or one artist’s plugin build, open Settings → DCC Apps, select an application, and click Edit. The dialog has two free-form fields: - Launch Arguments are extra command-line arguments, one per line. Dousen appends them to the launch. - Environment Variables are key and value pairs (click Add Row to add one) that Dousen sets on the DCC process. If you set a variable that Dousen also sets, your value wins, with these exceptions: Dousen always sets `DOUSEN_CORE_URL`, `DOUSEN_TOKEN`, `DOUSEN_CREDENTIAL_FILE`, and `DOUSEN_CREDENTIAL_ID` itself. - Dousen sets `DOUSEN_STARTUP_SCRIPTS` after your variables, so when the project has startup scripts for that DCC, its list replaces yours. - For Maya and Blender, Dousen always removes `PYTHONHOME`. - For the search-path variables above, Dousen adds its directory to your value. For anything the whole team needs, use startup scripts, so the configuration lives in the project. ## Related hooks - Custom validators load from `validators.extra_paths`. See Asset validation. - Standalone studio tools that run outside a DCC can register on the local relay and exchange events with everything else. See Bridge API. ## Keeping the addons up to date The Dousen addon for every DCC ships inside the DousenDesktop install, at `DOUSEN_HOME/python/dousen/addons/`, so there is no separate package to distribute. A DousenDesktop update installs the app, the bundled Python runtime, every DCC addon, and the Unreal plugin together. See Automatic updates for how updates are checked and verified. Artists get the new addon code when they accept the update and relaunch a DCC. Updates don’t change your startup scripts or custom validators, because those are set in the project’s pipeline settings on the server. ## When a script doesn’t load - Relaunch the DCC from DousenDesktop, because the script list is read at launch. - Look for these messages. DousenDesktop logs `Startup script not found` when it prepares the launch, and the DCC’s console shows `Startup script failed` followed by the error when a script raises one. - For depot paths, check that the file is mapped in the artist’s workspace and synced. Dousen logs an unmapped path and skips it. - See Troubleshooting for the general addon checklist. Previous ← Settings reference Next User and auth management → ## Tools and plugins — Dousen URL: https://dousen.io/docs/tools.html Summary: Explore the Dousen authoring tools and standalone Unreal plugins, their purpose, and how they fit into the studio workflow. Updated October 2026 Lists the standalone authoring tools and Unreal editor plugins in the Dousen family, whether each one is free or paid, and how to use them with the Dousen platform. Each tool does one authoring job and works on its own. Use it with the Dousen platform when you also want naming conventions, Jira tasks, Perforce changelists, and Publish history. For the DCC panels and Unreal plugin that DousenDesktop bundles, see DCC addons and Unreal Engine. ## Choose and try a standalone tool - Find your authoring task and host in the tables below. - Install the build for your host or engine version in a test environment, following the tool’s install instructions. - On a copy of a test file, run the tool’s authoring and export workflow before you connect it to Dousen. ## Free authoring tools These tools are free and work without a Dousen account, because their core authoring functions don’t need the studio server. You can still publish what they produce through Dousen. | Tool | Use it for | Initial host | |---|---|---| | DousenClips | Authoring and exporting game-animation clips. | Maya | | DousenBakeSet | Preparing repeatable high/low bake sets. | Maya | | DousenSockets | Authoring Unreal sockets and collision. | Maya | | DousenMorphs | Inspecting and managing morph targets. | Maya | | DousenTexel | Measuring and normalizing texel density. | Maya | | DousenMaterials | Aligning Substance outputs with Unreal. | Substance Painter | | DousenRetarget | Diagnosing and preparing animation retargeting. | Maya | ## Using authoring tools with the platform - Configure the project naming conventions for the asset. - Launch the host through DousenDesktop with the right project and task. - Author the asset and check it with the tool’s own workflow. - In the Publish tab, check the instances you want to publish, and check each one’s type and destination. - Validate and publish, then confirm the result in DousenDesktop’s Publish history. See Publishing assets. For example, in Maya the Publish tab lists each DousenClips clip as an instance next to the scene’s other instances. Check only the clips you want to export. See What becomes an instance? ## Standalone Unreal plugins | Plugin | Purpose | Model | |---|---|---| | DousenGraphKit | Procedural generators and filters for Texture Graph. | Free | | DousenActorProfiles | Stores default actor settings in any placeable asset and applies them to placed actors without overwriting per-actor overrides. | Paid | | DousenWorldDiff | Shows what changed in a World Partition or One File Per Actor world, property by property. | Paid | | DousenMaterialMigrator | Migrates Material Instance hierarchies to a changed master material and keeps intentional overrides. | Paid | | DousenCookLens | Explains what went into a cooked build, what it costs, and what changed between builds. | Paid | Each plugin has its own licensing. DousenActorProfiles has no restricted free edition. These plugins are separate from DousenUE, the platform integration plugin, and enabling DousenUE doesn’t install any of them. ## Get the right build Each tool and plugin has its own releases and compatibility. The Desktop download installs only the platform client, without them. During the studio beta, to get a build or compatibility details, contact the Dousen team with the product name and your host or engine version. Previous ← Self-hosted install Next Bridge API → ## Troubleshooting — Dousen URL: https://dousen.io/docs/troubleshooting.html Summary: Fixes for common Dousen problems: bridge connectivity, DCC addons that do not load, validation and publish errors, and Jira, Perforce, and sign-in errors. Updated October 2026 Describes how to find the stage where a publish failed, and lists the messages Dousen shows, with their causes and fixes, grouped by where you see them. Start with DousenDesktop’s Publish history tab, which shows the connected applications and what happened to each instance. Click Show connection events to see the traffic through the bridge, then open Logs for the detailed error. ## Find the failing stage first - Write down the project, Jira issue, source path, DCC version, Unreal project, and time of the failure. Read the error before you repeat the operation. - Check your Desktop sign-in and project. If a DCC doesn’t launch, check its executable or addon setup. If a connected app is missing from the list, see Bridge problems. - If validation fails, expand the rule and the affected instance. Fix the source data, or ask the project admin to review the rule. - If the export succeeds, open Publish history. For a failed import, read Unreal’s Output Log and check the import target, the source file, and any package-save errors. For an unconfirmed import, check the asset in the engine before you retry. - If Unreal saved the asset but the submit fails, check the Perforce changelists. If the Jira transition is missing, check the server-side Jira integration. - When you report a problem, include the failing stage, the exact message, the source objects that reproduce it, and the relevant part of the log, with passwords and tokens removed. For missing materials or an empty material picker, see catalog troubleshooting. ## A publish exported but didn’t complete An import is complete only when Unreal reports a saved package that matches it. For a failed result, fix the reported cause. For an unconfirmed result, check Unreal before you publish again. For retry rules and topology changes, see Recover from a failed publish and Interchange troubleshooting. ## Where logs and config live | What | Where | |---|---| | Desktop log | The Logs tab in the main window. Desktop also prints it to the terminal if you launched it from one. There’s no log file on disk. | | Desktop config | `config.ini` in `%LOCALAPPDATA%\Dousen\DousenDesktop\` on Windows, or in `~/.config/Dousen/DousenDesktop/` on Linux. | | Bridge token | `bridge.token` in the app data folder: `%APPDATA%\Dousen\DousenDesktop\` on Windows or `~/.local/share/Dousen/DousenDesktop/` on Linux. DousenDesktop creates a new token every time it starts. | | Blender addon log | `dousen_blender_bootstrap.log` in your temp directory. It’s written even when Blender has no console. | | Other DCC addons | They print `[Dousen] …` lines to the DCC’s own console: the Maya Script Editor, the MAXScript Listener, the Houdini console, or the Substance log. | | Unreal plugin | The editor’s Output Log, under the `LogDousenUE` category, and the project’s `Saved/Logs/` folder. | | Server (self-hosted) | `docker compose logs -f dousen-api` | Set the environment variable `DOUSEN_DEBUG=1` before you launch a DCC to make the addons print errors that they would otherwise swallow. By default they stay quiet, so that a pipeline problem never blocks an artist. ## The Dousen panel doesn’t appear in my DCC - Launch the DCC from DousenDesktop. Desktop injects the addon every time it launches the DCC, so a DCC that you start from a desktop shortcut has no Dousen panel. Dousen doesn’t register through the DCC’s own addon manager, such as Blender’s Preferences → Add-ons, so there’s nothing to enable there. See DCC addons. - Check the executable entry in Settings → DCC Apps. The entry’s type must resolve to the real application. Desktop handles an entry that points Blender at `blender-launcher.exe`, but a hand-added entry with an unrecognized id launches the app without an addon. - Read the DCC's console. If the addon fails to load, Maya, 3ds Max, and Houdini print `[Dousen] Failed to load addon: `. Blender prints `[Dousen] Failed to register addon: ` and also writes it to `dousen_blender_bootstrap.log` in your temp directory, which helps when Blender has no console. - Relaunch with `DOUSEN_DEBUG=1` if the console shows nothing at all. Older DousenDesktop builds could fail to load the Maya, 3ds Max, and Blender addons with no console output, even with debug logging on, because Dousen’s bundled Python modules hid the DCC’s own standard library modules. If tools are missing and the console is silent, update DousenDesktop. ## Bridge problems ### "Bridge not available." when publishing The DCC panel shows this when Desktop’s bridge didn’t confirm the request. Dousen sends a publish request only once, because the server may already have accepted it, so check Publish history before you publish again. Then check these, in order: - Is DousenDesktop running? The bridge runs inside it, so quitting DousenDesktop stops the relay. - Did you change the relay port? Restarting DousenDesktop while a DCC is open is fine, because the addon reads the bridge token again on every request. But a DCC keeps the relay port it launched with, so relaunch running DCCs after you change the port in Settings. - Does the Logs tab show `[Bridge] RPyC service failed to bind on port 8766 - reverting to stopped`? Then another program holds the port. See the first row of the table below. | Message | Cause | Fix | |---|---|---| | Desktop Logs: `[Bridge] RPyC service failed to bind on port - reverting to stopped` | Another program is using the relay port, so the bridge didn’t start. | Change the port in Settings → Connection → Bridge (the Bridge relay port field) and relaunch your DCCs. | | Desktop Logs: `[RPyC] Bridge failed; check pinned dependencies and port` | The bridge’s Python service failed to start. | Check that the relay port is free (see above). If it is and the message persists, update or reinstall DousenDesktop. | | Unreal Output Log: `Bridge registration failed ()` or `Bridge publish unconfirmed ()` | The Unreal plugin couldn’t reach DousenDesktop’s bridge. Status `503` means the request failed. | Start DousenDesktop, and check that `BridgeRelayPort` matches Desktop’s relay port. | | Unreal Output Log: `The RPyC bridge requires a loopback host` | `BridgeRelayHost` in `Config/DefaultDousenUE.ini` isn’t `localhost`, `127.0.0.1`, or `::1`. | Set `BridgeRelayHost` back to `localhost`, because the bridge always runs on the artist’s own workstation. | ### A DCC shows as disconnected even though it’s open DCC addons and the Unreal plugin renew their registration with DousenDesktop regularly. The addons renew every 10 seconds, and Desktop drops a registration that isn’t renewed within 90 seconds. So a DCC that freezes, for example during a long render or behind a modal dialog, leaves the connected list and comes back when it responds again. If the relay connection drops, the addons reconnect on their own. They wait 0.1 seconds before the first retry and double the wait up to 2 seconds. ### Events published but nothing happens in the receiving app - To check that the event reached the relay, click Show connection events in Publish history. - An event can name a target app, so a Send to Painter with Painter closed goes nowhere. Check that the receiving app is in the connected list. - Live events go only to the apps that are connected when the event is published. An app that was closed then doesn’t get the event later, and the relay keeps only the last 200 events as history. Check the publish state and the destination before you publish again. ### A custom tool shows stale task context after Desktop restarts Custom tools connect through the bundled `BridgeClient`, which handles the bridge token. After Desktop restarts, discard any task context your tool cached and wait for a new `task.context` event. See Bridge API. ### A long-running DCC session ignores a convention or setting change Addons cache the project’s conventions and pipeline settings for 5 minutes, so a change can take that long to arrive. If it still doesn’t arrive, check the addon’s credential. DousenDesktop launches each DCC with `DOUSEN_CREDENTIAL_FILE` and `DOUSEN_CREDENTIAL_ID`, and the addon reads the current access token from that file for every request. `DOUSEN_TOKEN` is used only when neither variable is set, for explicit or self-hosted launches. - If DousenCore can’t be reached, the addons keep using the last values they fetched. - If the credential file is missing, expired, or belongs to a different studio, the addons send no token, drop their cached values, and use defaults until the credential is valid again. Sign in to the right studio in Desktop, relaunch the DCC from Desktop, and collect again before you publish. ## Working offline When DousenCore is unreachable, DousenDesktop queues two kinds of operations on disk: source-asset metadata upserts (what an artist published from a DCC) and changelist opens that go through the server route. They’re sent automatically when the server answers again. Submitting a changelist and the Jira sync need a live connection. Desktop drops a queued item that the server rejects with a 4xx response, and it clears the queue when you sign out. See Working offline. The offline queue is a preview feature. Treat it as best-effort, and don’t assume that every action is safe during an outage. If Desktop hasn’t reached DousenCore for 14 days, the queue stops accepting new work and shows "Offline too long — reconnect to Dousen to verify your license before more changes can sync." Reconnect before then if you can. ## Validation and export problems These messages appear when an export or publish won’t go ahead. For the rules themselves, see Asset validation. The Publish tab (Maya, 3ds Max, Substance Painter, Substance Designer) validates and then exports when you click Publish. | Message | Cause | Fix | |---|---|---| | "Publish stopped: fix validation errors before exporting" (Publish tab log) | At least one checked instance has an error-severity result, so Publish validated and then stopped before it exported anything. | Expand the failing results, fix the objects or use Fix, then click Publish again. | | "N warning(s) found. Publish anyway?" | The checked instances have only warnings. The default answer is No. | Choose Yes to publish through the warnings. If you choose No, the Publish tab shows "Publish cancelled — N warning(s) unresolved" and exports nothing. | | "Files locked by another user" or "Files locked: …" | Another Perforce user has locked a file that the export would write. | See Perforce problems. | | A rule is stricter, looser, or missing compared with what you remember | Your project’s naming convention can turn on a rule that’s off in the baseline, change a warning to an error, or tighten a parameter such as the triangle budget or texture limit. | Ask your admin to check the effective rule set on the project’s Validators tab in the web portal. | To see what an artist ran into, open Validation history in the portal, or ask for the results in their Dousen panel. For the rules that run, see Which rules run. ## Jira problems | Message | Cause | Fix | |---|---|---| | "Jira sign-in failed — check your Jira email and API token in Settings." | Jira rejected your credentials (401 or 403). Desktop pauses task polling. | Enter the account email and a new API token from your Atlassian account in Settings → Jira, click Test Connection, and save. Polling resumes when you save Settings. | | "Offline — can't reach Jira (). Retrying automatically." | A network problem, such as a wrong base URL, a VPN, or no connection. | Nothing to do. Polling backs off (60 seconds, then 5 minutes). When Jira is reachable again, Desktop shows "Connection restored." | | "✗ Fill in all Jira fields first" in Settings (or "Fill in all Jira fields first." in onboarding) | The Jira base URL, email, and token are all required. | Fill in all three. The base URL is your full Jira Cloud site, for example `https://yourstudio.atlassian.net`. | | "✗ Failed" after Test Connection | Jira didn’t answer HTTP 200 within 5 seconds. | Check the base URL, the email, and the token, and check that you can reach Jira from this machine. | | The task list is empty but you have work assigned | My tasks shows only the issues assigned to you that aren’t in a Done status category (`assignee=currentUser() AND statusCategory != Done`). | Check the assignee and status of the issues in Jira. | ## Sign-in and session problems | Message | Cause | Fix | |---|---|---| | "Session active on another device. Please log in again." (tray notification) | Dousen allows one active device per account, and another sign-in, by you or someone using your account, took over the session. The old device keeps working until its next 60-second heartbeat or token refresh, so the two can overlap for up to a minute. | Sign in again to take the session back. If you didn’t sign in anywhere else, tell your admin. | | "Session expired. Please sign in again." | The background token refresh failed, usually after a long time offline or a sign-out on the server. | Sign in again. If it keeps happening immediately, the server may be unreachable. Click Test Connection in Settings → Connection. | | "Sign-in timed out. Please try again." | Sign in with Browser got no callback for 5 minutes, for example because you closed the tab. | Click Sign in with Browser again. Desktop doesn’t leave a listener open afterward. | | "Login failed" in the browser tab | The browser’s callback to Desktop was invalid or reported an error, for example because the server rejected the authorize step. | Start the sign-in again from DousenDesktop instead of reloading the browser tab. | | "Seat limit reached — contact your administrator." on the portal sign-in page | The instance uses directory sign-in, and a new user can’t be created because every seat is in use. | Deactivate a user who has left, or ask for a license with more seats. See User and auth management. | Sign in with Browser opens your system browser to a one-time OAuth (PKCE) flow, with a local callback listener on a loopback port that the operating system picks. The first-run setup wizard (server, Jira, Perforce workspace, Unreal project, DCC discovery) appears only on a fresh install, and DousenDesktop skips it after it completes. To set a machine up again without reinstalling, click Re-run Setup on the sign-in screen (see Desktop app) instead of deleting config files. ## Auto-update problems | Message | What it means | |---|---| | "SHA-256 checksum mismatch — download may be corrupted" | The downloaded installer doesn’t match the published hash, so Desktop refuses the update. Click Retry. If it keeps failing, a proxy or CDN cache may be serving a bad copy, so download the installer manually. | | "Update signature verification failed — the installer is not signed by Dousen. Refusing to install." | The installer’s signature doesn’t verify, so it may have been tampered with or come from an untrusted mirror. Don’t bypass this. Get the installer from the official release channel. | | "Update manifest signature verification failed — the advertised version is not signed by Dousen. Refusing to install." | The update manifest’s own signature doesn’t verify. Get the installer from the official release channel. | | "Manifest missing sha256 — refusing unsigned update" | The update manifest is malformed or unsigned, which is a server-side release problem. Report it. | | "This build has no update-signing key configured; refusing to install an unverifiable update. Please download the update manually." | This build can’t verify update signatures, so it won’t install any update. Download the installer manually from the official release channel. | In every case, Desktop refuses the update, and the dialog shows a red "✗ Download failed: …" status with a Retry button. The version you’re running isn’t touched, so a failed update never leaves you on a broken install. ## Perforce problems | Message | Cause | Fix | |---|---|---| | "Failed to start p4. Is it installed and on PATH?" | The onboarding workspace steps run the `p4` command line directly, and Desktop can’t find it. | Install the Helix command-line client, and check that `p4` works in a terminal. | | "Perforce server/user/workspace not fully configured — set them in Settings" | Some of the Perforce server, user, and workspace are set in Desktop, but not all three. | Fill in all three in Settings, or clear them all. | | Status bar: "P4: not connected" or "P4: connection unavailable" | Perforce didn’t report a workspace, or the check failed. Hover over the label to see the reason for the second message. | Check the project’s Perforce server and workspace in Settings → Projects, and check that you’re signed in to Perforce. | | "Depot check failed: …" or "Unable to determine whether the depot is a stream. Check the depot path and try again." | The Check button in the Workspace step ran `p4` commands that failed. The message includes `p4`'s own error. | Check the depot path, the server, and your Perforce sign-in, then run Check again. | | "Workspace creation failed. Check P4V before retrying: …" | The message ends with `p4`'s own error. The usual causes are a bad depot path, or a workspace name that already exists on another host. | Check P4V first, because the workspace may already exist. Then fix the field the error names and retry, or create the workspace in P4V and run Check again. | | "A Perforce operation is already running." | You started a second changelist open, submit, or unshelve while the first was still running. | Wait for the first operation to finish. | | "This changelist has no opened files. Move the intended files into it in P4V." | You clicked Submit changes, but the task’s numbered changelist is empty. Desktop doesn’t move files out of the default changelist. | Move the files you want into the task’s changelist in P4V, then submit again. | | "Perforce timed out; the outcome may be unknown. Check P4V before retrying." or "Submit outcome is unknown. Check Perforce before retrying." | A `p4` command didn’t finish or didn’t confirm its result. | Check the changelist in P4V before you retry. Dousen recovers an interrupted open or submit through the markers in the changelist description. | | "Multiple Perforce changes have this task marker; resolve them in P4V." | Two pending changelists carry the same Dousen task marker in their descriptions. | Delete or merge the extra changelist in P4V, then try again. | | Export blocked: ": locked by (CL n)" | Someone else has the file locked, so the lock check stops the export before it overwrites their work. | Coordinate with that user, or wait for their submit. | | Files are missing after onboarding created a workspace | Workspace creation doesn’t sync. | Sync from P4V or UnrealGameSync before you start work. | | Status bar shows "P4: " instead of "(classic)" | This is informational. The workspace is a stream workspace. | Hover over it to see the workspace name and the server version. | Inside a DCC, the lock, checkout, and changelist features use P4Python if the DCC’s own Python can import it, and otherwise switch silently to the `p4` command line. If neither is available, those calls return nothing instead of an error, so lock status can go quiet without a message. If the lock rows stop updating, see Perforce. ## Unreal Engine problems For the full plugin reference, see Unreal Engine. | Symptom | Cause | Fix | |---|---|---| | Assets don’t reimport automatically | Auto-reimport is off, or the plugin can’t reach DousenDesktop’s bridge. | Check, in order, that `bAutoReimportOnBridgeEvent` is `true`, DousenDesktop is running, `BridgeRelayPort` matches Desktop’s relay port, and the Output Log has no `Bridge registration failed` warning from `LogDousenUE`. | | Output Log: `Refusing to contact DousenCore over cleartext HTTP on a non-loopback host` | The plugin allows plain HTTP only to a loopback host. | Set `ServerScheme=https` in `Config/DefaultDousenUE.ini` and use an HTTPS address for the server. | | Naming-convention checks are missing, and imports land in odd paths | `ProjectId` is empty in `Config/DefaultDousenUE.ini`, so Dousen skips conventions. | Set `ProjectId` to the project’s UUID. If the editor has `DOUSEN_PROJECT_ID` in its environment, it uses that value instead. | | Unreal is missing from the "Send to Unreal" lists | The editor appears as a connected DCC only while it’s open with the plugin loaded. | Open the editor, or turn on headless import in DousenDesktop (Settings → Unreal) so publishes still land. See headless import. | ## Server problems (self-hosted admins) | Message | Cause | Fix | |---|---|---| | Log: `DOUSEN_LICENSE_KEY not set and no persisted license found — Core is locked (fail closed)`, or `DOUSEN_LICENSE_PUBLIC_KEY_PEM not set — … locked (fail closed)` | No license is configured, so DousenCore is locked. | Set `DOUSEN_LICENSE_KEY` and `DOUSEN_LICENSE_PUBLIC_KEY_PEM` in `.env` and restart. See Self-hosted install. | | Log: `license validation failed — Core is locked (fail closed)` | The token is malformed, doesn’t match the public key, or expired more than 14 days ago. The `error` field says which. | Paste `DOUSEN_LICENSE_KEY` and `DOUSEN_LICENSE_PUBLIC_KEY_PEM` again exactly as issued. For an expired license, get a renewed key and restart. | | Log: `DOUSEN_LICENSE_PUBLIC_KEY_PEM is not a valid PEM public key (…) — Core cannot verify any license and is locked (fail closed)` | `DOUSEN_LICENSE_PUBLIC_KEY_PEM` isn’t a valid PEM public key, so Core starts locked. | Paste the key again exactly as issued, inside double quotes. See Self-hosted install. | | Log: `LICENSE EXPIRED — operating in grace period. Renew at https://dousen.io/billing` | The license expired, but the server is inside its 14-day grace period. It keeps running and logs the remaining days at each startup. | Renew before the grace period ends. The portal has no countdown, so watch the logs. | | Log: `license expiry recheck failed: license expired and grace period has ended … — Core is now locked` | The grace period ended while the server was running. DousenCore checks the expiry every hour. | Put a renewed `DOUSEN_LICENSE_KEY` in `.env` and restart. | | Log: `license by control plane: … — Core is now locked` | The control plane rejected the license heartbeat with a JSON 403. | Resolve the cause with Dousen billing, for example a payment or a seat overage. A locked instance retries every hour. After `revoked` or `cancelled`, Core remembers the lock across restarts, so you need a newly issued license. | | Log: `license heartbeat got a 403 that isn’t a control-plane verdict` | A proxy or firewall blocked the heartbeat. Core stays in its current state and tries again at the next heartbeat. | Allow the instance to reach `DOUSEN_CONTROL_PLANE_URL`, or set it to empty to turn the heartbeat off. | | Requests return 403 with `"code": "unlicensed"` and "Dousen Core is unlicensed: …" | DousenCore is locked. `/health` still answers, so the container looks healthy. | Read the reason after "unlicensed:" and find the matching log line above. | | Log: `JWT secret must be at least 32 bytes, got N` (the container restarts repeatedly) | `DOUSEN_JWT_SECRET` is shorter than 32 bytes. | Set a random value of at least 32 bytes, for example `openssl rand -hex 32`. | | "Seat limit reached (n/n). Upgrade your plan to add more users." | Every seat is in use, and pending invites count. | Free a seat with Deactivate or Remove, or get a license with more seats, then try again. See User and auth management. | | Users page: " was created, but SMTP isn't configured on this instance — no email was sent." Or, after Send reset link: "SMTP not configured — no email sent. The link is logged only at debug level" | No mail server is configured, so Dousen can’t email the link. The invite or reset itself worked. | Configure SMTP, or take the link from the log at the `debug` level with `RUST_LOG=info,dousen_api::email=debug`. See Self-hosted install. | | Jira webhook returns 401 | The signature didn’t verify. The secret in Jira’s webhook doesn’t match `DOUSEN_WEBHOOK_SECRET`. | Copy the secret again on both sides. | | Jira webhook returns 503 | `DOUSEN_WEBHOOK_SECRET` isn’t set, so the server refuses unsigned webhooks by default. | Set the secret. For development only, `DOUSEN_ALLOW_INSECURE_WEBHOOK=true` turns the check off. Never use it in production. | If you’re still stuck, contact support and include the relevant log: the Logs tab, a DCC console, or the `LogDousenUE` output. Previous ← Bridge API ## Unreal Engine — Dousen URL: https://dousen.io/docs/unreal.html Summary: Install and configure the DousenUE plugin, see how published assets are imported into Unreal Engine, and open an asset’s source file in a DCC. Updated October 2026 Describes how to install and configure the DousenUE plugin, how published assets are imported into Unreal Engine, and how to open an asset’s source file from the Content Browser. Supported engine versions: Unreal Engine 5.7 and 5.8. ## Install the plugin - In DousenDesktop, open Settings → Unreal. Under Project (Global Fallback), set the path to your `.uproject` file. An entry for the project on the Projects tab overrides this path. - Under Install Plugin, click Install into .uproject. Desktop copies the bundled DousenUE plugin into the project’s `Plugins` folder. You can also copy the `DousenUE` folder into `Plugins` yourself. - Open the project in Unreal Editor. If DousenUE isn’t enabled, enable it in the Plugins window and restart the editor when prompted. DousenUE needs the PythonScriptPlugin and Interchange plugins, and Unreal enables them with it. If you build the plugin from source, build it for your project’s engine version. Use the plugin from the DousenDesktop version you run, and try a new version in a test project first. ## Configure the plugin The plugin reads its settings from the `[/Script/DousenUE.DousenProjectSettings]` section. Its defaults are in the plugin’s own `Config/BaseDousenUE.ini`. To override them, create `Config/DefaultDousenUE.ini` in the Unreal project with the keys you want to change. Commit the file to source control so everyone on the project gets the same values. It holds no credentials. INI`[/Script/DousenUE.DousenProjectSettings] ServerScheme=https ServerHost=core.example.com ProjectId=YOUR_PROJECT_UUID BridgeRelayHost=localhost BridgeRelayPort=8766 bAutoReimportOnBridgeEvent=true bUseDousenImportPipeline=true bRefreshConventionsOnReimport=false` Replace the host and the UUID with your own. For development against a DousenCore on your own machine, use `ServerScheme=http` and `ServerHost=localhost:8080`. | Key | Default | What it does | |---|---|---| | `ServerScheme` | `https` | The scheme of the DousenCore URL. The plugin refuses `http` unless `ServerHost` is `localhost`, an address that starts with `127.`, or `::1`. | | `ServerHost` | `localhost:8080` | The host and port of DousenCore, without the scheme. | | `ProjectId` | empty | The DousenCore project UUID. Without it, the plugin doesn’t fetch conventions or report the material catalog. | | `BridgeRelayHost` | `localhost` | The host of DousenDesktop’s bridge: `localhost`, `127.0.0.1` or `::1`. For any other value, the plugin logs “The RPyC bridge requires a loopback host” and doesn’t connect. Desktop runs on the same machine as the editor, so keep this value even when `ServerHost` points at a remote server. | | `BridgeRelayPort` | `8766` | The port of DousenDesktop’s bridge. It must match the bridge port in Desktop’s settings. | | `bAutoReimportOnBridgeEvent` | `true` | Lets the open editor import and reimport published assets. If it is `false`, the plugin refuses the imports that Desktop sends to the editor. | | `bUseDousenImportPipeline` | `true` | Imports every Dousen asset with a Dousen Interchange pipeline, so the import settings don’t depend on the project’s default pipeline stack. Set it to `false` to use the project’s own Interchange configuration. | | `bRefreshConventionsOnReimport` | `false` | Keeps the conventions that were stored with an asset when you reimport it. Set it to `true` to refresh them from the project’s current conventions. Existing asset names never change. | | `MaterialCatalog` | not set | The path of the material catalog Data Asset, which must be in your project’s `/Game` content. See Material catalog and texture assignments. | Environment variables on the editor process override the INI. `DOUSEN_CORE_URL` overrides `ServerScheme` and `ServerHost`, `DOUSEN_PROJECT_ID` overrides `ProjectId`, and `DOUSEN_BRIDGE_PORT` overrides `BridgeRelayPort`. The plugin signs its DousenCore requests with the access token that Desktop writes next to `bridge.token` when you sign in. Sign in to Desktop first. If `ServerScheme` and `ServerHost` don’t match the server that Desktop is signed in to, the plugin sends its requests without credentials. ## Check your first editor session - Start DousenDesktop, sign in, and select the project and task. - Start Unreal Editor with the project. In Desktop’s Publish history tab, check that Unreal appears under Connected apps. If it doesn’t, see Troubleshooting. - From a DCC, publish one small instance that has a valid type and tags. In Desktop, wait for Imported and saved in Unreal, and then find the asset in the expected Content Browser folder. - If the project uses catalog materials, complete Create the catalog in Unreal first. Then publish an instance with a material assignment, and check the imported Material Instance. - Right-click the imported asset and choose Open in DCC. Check that the source file opens in the DCC you expect. ## How the plugin connects The plugin calls DousenCore over HTTP for your project’s conventions and the material catalog. For publishes and task context, it connects to the DousenDesktop bridge on the same machine, port `8766` by default. When the editor starts, the plugin registers with the bridge as `unreal`, and then again every 30 seconds. The registration includes a second port on `127.0.0.1` that Desktop uses to send imports to the open editor. See Bridge API. ## Publish and import When you publish an instance from a DCC, Desktop records it in Publish history and sends the import to the project set in Settings → Unreal. If an editor is open, Desktop checks that it has that project open and sends the import to it. Otherwise, Desktop imports the asset in the background if headless import is on. Dousen works out the asset’s name and folder from your project conventions, imports or reimports the asset, applies the materials, and saves the packages. Desktop shows Imported and saved in Unreal only after the packages are saved. To decide whether to retry, see Follow a publish in Publish history. ## Reimport and Interchange Dousen imports with Unreal’s Interchange framework. When you publish an instance again, the meshes and animations that already exist in Unreal reimport and keep their asset paths. Meshes that you add to the source scene wait for your approval, and meshes that you remove stay in the project. To review and approve these changes, right-click an imported mesh in the Content Browser and choose Review instance topology. The menu item appears only for static and skeletal meshes that Dousen imported, and only when `bUseDousenImportPipeline` is on. For the review steps, geometry profiles and project import stacks, see Unreal Interchange. Import profiles come from the project conventions that the plugin fetches from DousenCore, so they need a current DousenCore. Self-hosted studios must update Core to use them. ## Naming and destination Dousen builds an asset’s name and Content Browser folder from the asset type and tags in the published event, using your project’s naming conventions. The plugin fetches the conventions from DousenCore for the project in `ProjectId` and refreshes them every 5 minutes. Without conventions, the plugin can’t import a new asset, and reports “Project conventions unavailable; fetch conventions before importing new assets”. Before it creates an asset, Dousen checks the required tag dimensions, the allowed values, the taxonomy, the package name and whether the asset already exists. A later reimport doesn’t rename the asset, even if you change the naming rules. ## Material catalog and texture assignments The material catalog lists the materials that artists can assign to a mesh in a DCC. Screenshots on this page use a sample project. Admins: create a Dousen Material Catalog Data Asset in the project’s content, and set `MaterialCatalog` in `Config/DefaultDousenUE.ini` to its path. Saving the asset while you are signed in to Desktop as an admin reports the catalog to DousenCore. The portal shows the report, read-only, under Projects → your project → Materials. Artists: in the DCC, load the catalog, choose a material for each mesh slot or texture set, set its textures, and publish the instance. On import, Dousen applies the assignments to each mesh and binds the textures into the matching slots of its material instances. On static meshes, it also sets Nanite from the catalog’s Allow Nanite values. For the full rules and the setup steps, see Materials and textures. ## Open the source file in a DCC - In Desktop, select the task you published the asset under. The plugin takes the Jira key from that task. - In the Content Browser, right-click a static mesh, skeletal mesh or texture, choose Open in DCC, and pick an application. Desktop finds the source file from the project, the Jira key and the asset name. If needed, it syncs the file from Perforce or reads it from a configured cloud folder. Then it launches the DCC. The menu lists the apps in Desktop’s app list and the apps registered over the bridge. It refreshes every 60 seconds, so it can take up to a minute to update after you start Desktop. If it has no apps, the entry reads Open in DCC (no DCCs registered) and is disabled. Start Desktop and check that Settings → DCC Apps lists your DCCs. ## Metadata and search Dousen stamps metadata on each imported asset. Convention tags are stored as `Dousen.Convention.`, computer-vision tags as `dousen_cv_*`, and, when the event carries them, the published source as `Dousen.PublishedDepotPath` and `Dousen.PublishedRole`. To list an asset’s `dousen_*` metadata, such as its computer-vision tags, right-click a static mesh, skeletal mesh or texture and choose Show Dousen Tags. To find assets by tag, go to the Tag Search section of the Dousen tab, enter tag keys and values, and click Search. The Content Browser shows the matching assets. You can search these computer-vision tags: `dousen_cv_object_class`, `dousen_cv_poly_tier`, `dousen_cv_has_uvs`, `dousen_cv_is_skinned` and `dousen_cv_style_hint`. Dousen sets only `dousen_cv_poly_tier`, `dousen_cv_has_uvs`, and `dousen_cv_is_skinned`, so `dousen_cv_object_class` and `dousen_cv_style_hint` match only tags that you add yourself. ## Import when the editor is closed In Desktop, open Settings → Unreal. Under Headless Import (UE Closed), select Auto-import via UnrealEditor-Cmd when UE is not running and set the path to `UnrealEditor-Cmd`. When no editor is open, Desktop then imports published assets in the background. Desktop confirms a headless import only when it receives a valid receipt. If the receipt is missing or invalid, or the editor crashes or can’t save, Publish history shows the publish as failed or unconfirmed. Check the destination before you retry. ## Troubleshooting | Problem | What to check | |---|---| | Unreal isn’t connected | The plugin is enabled, `BridgeRelayHost` is `localhost`, `127.0.0.1` or `::1`, `BridgeRelayPort` matches Desktop’s bridge port, and Desktop is running. Then check Desktop’s Logs tab. | | A new import is rejected | The plugin has the project’s conventions (`ProjectId` is set and the server is reachable), the asset type and tags are valid, and the name and folder don’t collide with an existing asset. | | A mesh you added doesn’t appear | A reimport doesn’t import new meshes. Use Review instance topology on an imported mesh. | | The asset was imported, but the publish isn’t confirmed | In Unreal, check that the asset and its packages were saved, and read the result in Publish history. Don’t retry until you know what was imported. | | Open in DCC opens nothing | Desktop’s Logs tab gives the reason. Common causes are no selected task, a source file that isn’t on disk, or a DCC that isn’t in Settings → DCC Apps. The asset path in Unreal isn’t the source file’s name, so don’t search the disk for it. | | An animation uses the wrong skeleton | Unreal uses the `skeleton` the event names. Without one, it follows the rig that the animation references, and then looks in the destination folder. See Export events from DCCs. | | A large source file freezes the editor | Part of the import and the save run on the editor’s game thread, so a large file can make the editor unresponsive. | For more help, see Interchange troubleshooting and Recover from a failed publish. Previous ← Source repositories Next Naming conventions → ## User and auth management — Dousen URL: https://dousen.io/docs/user-management.html Summary: Invite and manage users, and see how roles and sign-in methods work on a Dousen studio instance. Updated October 2026 Describes how to invite and manage users on a studio instance, how roles and sign-in methods work, and how cloud organization membership relates to them. ## Invite an artist and verify access These steps work on a self-hosted instance and on a cloud studio. For how each type of studio handles the invite, see Invites on a self-hosted instance and Invites on a cloud studio. - Sign in to the web portal as an Admin, open Users, and click Invite User. - Enter the email, display name, and role, then click Send invite. You don’t set a password. - Read the message above the list. With local passwords or on a cloud studio, the new row shows a Pending invite badge until the person sets a password or accepts the cloud invitation. - Ask the artist to accept the invite and sign in to DousenDesktop against the studio URL. On a self-hosted instance with local passwords, they set a password of at least 8 characters from the emailed link. - Have them select the intended project. Check that their normal artist workflow works and that admin-only configuration isn’t available to them. If the invite is refused, check the available seats and your own role. For a directory or cloud account, fix the directory account or the organization membership instead of setting a local password. To create the first admin on a new self-hosted instance, see Self-hosted install. After you change a role, ask the person to sign in and check that they have the access you expect. ## Cloud roles and studio roles | Service | What it manages | Roles | |---|---|---| | DousenControl | Organizations, billing and subscriptions, and the DousenCore instance that serves each tenant. Studios don’t run this service themselves. | `owner`, `admin`, `member` | | DousenCore instance | Projects, conventions, validators, changelists, source assets, and the studio’s own users. This is the "studio instance" in the rest of these docs. | `Admin`, `Producer`, `Artist` | Cloud roles and studio roles are stored in separate databases and checked independently. A DousenControl role only sets a person’s starting role on an instance, the first time they sign in through the cloud. See Which role wins. ## Roles on a studio instance The whole web portal (`/portal/*`) requires the `web_portal` license feature, and every console page requires the Admin role. The console covers projects, conventions, validators, pipeline settings, users, changelists, assets, the health dashboard, the validation history page, and the material-catalog viewer. | Role | Console (`/portal/*`) | Self-service account (`/portal/account`) | |---|---|---| | Admin | Full access to every console page. | Yes. | | Producer | Redirected to `/portal/account` on any console route. | Yes. | | Artist | Redirected to `/portal/account` on any console route. | Yes. | The JSON REST API doesn’t redirect. Each admin-only endpoint checks the role itself and returns 403 to anyone else. | REST endpoint | Who can call it | |---|---| | POST /api/projects | Admin | | PUT /api/projects/:id | Admin | | PUT /api/projects/:id/conventions | Admin | | PUT /api/projects/:id/settings | Admin | | PUT /api/projects/:id/validators | Admin | | POST /api/projects/:id/material-catalog | Admin (the matching GET isn’t admin-only) | | POST /api/validator-catalog | Admin (the matching GET isn’t admin-only) | | Changelist submit and unshelve (`/api/vcs/submit`, `/api/vcs/unshelve`) | The user who opened the changelist, or an Admin | ## Invite and manage users Admins manage a studio instance’s users on the portal’s Users page. Screenshots on this page use sample accounts. | Action | Where to do it | |---|---| | List users and check seats | Open Users in the portal sidebar. The header shows the seat count, for example 4 / 10 seats used. | | Open the invite form | Click Invite User. When every seat is in use, this button is replaced by Upgrade plan. | | Invite a user | Fill in Email, Display Name, and Role, then click Send invite. | | Resend an invite | Click Resend invite in the row of a pending invite, and confirm. On a self-hosted instance, Core sends a new 7-day link, and the earlier link stops working. | | Cancel a pending invite | Click Remove in the row of a pending invite, next to Resend invite. A pending local invite is deleted and frees its seat. For a cloud invite, see Invites on a cloud studio. | | Change a user’s role | Choose the new role in that user’s row, then check the saved selection. | | Deactivate a user | Click Deactivate in the user’s row, and confirm. See Deactivate and reactivate a user. | | Reactivate a user | Click Reactivate in the row of a user with a red Deactivated badge, and confirm. The user must sign in again. | | Send a password-reset link | Click Send reset link in that user’s row, then read the message that replaces the button. | ### Invites on a self-hosted instance - Local passwords: Invite User creates the account with no password and emails the invitee a link to set one. The link is valid for 7 days. The email goes out over the instance’s own SMTP server (see Self-hosted install). - Directory sign-in (LDAP): Invite User creates the account with the role you chose and sends no email. The person signs in with their directory credentials, and that first sign-in attaches to the account, provided that Dousen has a user search base (see Self-hosted install). The banner reads " can now sign in with their directory credentials". ### Invites on a cloud studio On a cloud studio, Invite User creates the row with the role you chose and asks DousenControl to send a team invitation. DousenControl owns the invitation email, the seat check, and the acceptance step. No password is set in the portal, and the portal’s sign-in page redirects to cloud sign-in. - The invitee becomes a `member` of the organization in DousenControl, whatever role you choose. Their first cloud sign-in attaches to the pending row, which keeps the role you chose on the studio instance. - The invitation expires after 7 days and holds a seat until then. The row then shows an Invite expired badge and stops counting against seats, but it still attaches with its chosen role if the person signs in later. - Remove cancels the emailed invitation first, so the link stops working, and then deletes the row. If the person has already joined the organization, Dousen refuses and tells you to remove them from the team in DousenControl. - Resend invite appears only on an expired invite. It asks DousenControl for a new invitation and counts the row against seats again. ### Invite messages After you click Send invite, the Users page shows one of these messages: | Message | What it means | |---|---| | Invitation sent to | The invite email was handed to the mail server (self-hosted) or to DousenControl (cloud). | | was created, but SMTP isn't configured on this instance — no email was sent. | The account exists, but nothing was emailed. The message adds that the link is logged only at debug level, with the hint `RUST_LOG=info,dousen_api::email=debug`. Configure SMTP and click Resend invite, or take the set-password link from the server log (see Self-hosted install). | | was created, but the invite email failed to send | SMTP is configured but the send failed. Read the server log, fix the cause, then click Resend invite. | | was created, but invite emails for this address are rate-limited right now | Each address can receive only 3 invite or reset emails per hour. Click Resend invite again in a few minutes. | | is already a member of the org — their role will apply when they first sign in to Dousen. No invite email was sent. | Cloud only. The person already belongs to the organization in DousenControl, so no invitation was sent. | If a user with that email already exists, the invite is refused with "A user with already exists". Change their role in the list instead, or use Resend invite if they haven’t set up their account yet. With directory sign-in, inviting an existing email updates that account’s role and display name instead. Integration reference: invite request The invite form posts `email`, `display_name`, and `role` (`admin`, `producer`, or `artist`), with no password field. Like every portal form, the request needs the session cookie and the session’s CSRF token, as a `csrf_token` form field or an `X-CSRF-Token` header: HTTP`POST /portal/users HTTP/1.1 Content-Type: application/x-www-form-urlencoded csrf_token=…&email=jane%40studio.com&display_name=Jane+Doe&role=artist` The response redirects to `/portal/users?feedback=&email=`. The `feedback` codes are `invite_sent` and `cloud_invite_sent` (invitation sent), `invite_smtp_unconfigured` (created, no email because SMTP isn’t configured), `invited_directory` (directory account created), `cloud_already_member`, `invite_failed`, and `invite_rate_limited`. The page shows nothing for any other value. ### Deactivate and reactivate a user When someone leaves the studio, click Deactivate in their row. The user can’t sign in by any method, and their sessions end on their next request. Their changelists and history stay. A deactivated row shows a red Deactivated badge and a Reactivate button. - You can’t deactivate your own account, the last active admin, or a pending invite. Use Remove for an invite. - On a self-hosted instance, deactivating a user frees their seat, and Reactivate takes one again. If no seat is free, it fails with the seat-limit message. On a cloud studio, deactivating doesn’t free a seat. To free it, remove the member from the Dousen organization in the cloud dashboard. - Inviting the email address of a deactivated user fails and tells you to use Reactivate. ### Seats Inviting a user checks the seat limit before it creates the row, and pending invites count. On a self-hosted instance, the limit is the seat count in your license, and an invite holds a seat from the moment you send it. If no seats are left, the invite fails with "Seat limit reached (n/n). Upgrade your plan to add more users." On a cloud studio, DousenControl checks the organization’s limit, and a refused invite shows "seat limit reached — upgrade your plan to invite more members". To free a seat on a self-hosted instance, Deactivate a user or Remove a pending invite. See Deactivate and reactivate a user. An instance without a valid license is locked and refuses portal requests. Only `DOUSEN_DEV_UNLICENSED=true`, for local development, removes the seat limit. ## Password reset and recovery Users can request a reset link themselves, or an admin can send one from the Users page. Both use the same mechanism. | Route | Who | Purpose | |---|---|---| | GET/POST /portal/forgot-password | Anyone, not signed in | Request a reset link by email. | | GET/POST /portal/reset-password | Anyone with a valid token | Use the token to set a new password. Invite links open this page too. | | POST /portal/users/:id/send-reset | Admin | Send a reset link to a user from the Users page. | A reset or invite token is a random value that DousenCore stores as a SHA-256 hash. A reset link is valid for 1 hour and an invite link for 7 days. A token allows 5 attempts, and each email address can request 3 links per hour, counting invites and resets together. A new password must be at least 8 characters. The self-service page shows the same response whether or not the account exists, so it doesn’t reveal which emails have accounts. A message replaces the Send reset link or Resend invite button: | Message | What it means | |---|---| | Reset link sent | SMTP is configured and nothing failed. To avoid revealing which accounts exist, this message also appears when no email was sent: for a directory or cloud account, or when the address reached its hourly limit. | | SMTP not configured — no email sent. The link is logged only at debug level (RUST_LOG=info,dousen_api::email=debug) | No email was sent. To get the link, see Self-hosted install. | | Failed to send — check server logs | SMTP is configured, but the send failed. | | Rate-limited — try again in a few minutes | Resend invite only. The address reached its hourly limit. | | This user isn't waiting on an invite | Resend invite only. The person already set a password or signed in, so there’s nothing to resend. | Directory and cloud accounts have no local password, so reset links don’t apply to them. Those users always sign in through their directory or the cloud. The Send reset link button still appears on their rows, but no email is sent. ## Sign-in methods | Method | How it works | Role on first sign-in | |---|---|---| | Local password | `DOUSEN_AUTH_MODE=local` (the default). DousenCore checks the password against the instance’s own Argon2 hash. | The role the admin chose in Invite User. | | Directory (LDAP/AD) | `DOUSEN_AUTH_MODE=ldap`. Dousen binds directly as the signing-in user, so you don’t need a service account, and empty passwords are always rejected. | The account is created on the first successful bind. Members of `DOUSEN_LDAP_ADMIN_GROUP` become Admin and everyone else becomes Artist. This path never assigns Producer, and it needs a working user search base and filter to read group membership. An admin can create the account earlier with Invite User and choose its role. | | Browser OAuth (cloud) | DousenDesktop opens the browser to DousenControl’s `/oauth/authorize`, using PKCE (S256) and a local loopback callback server. | Set by the cloud organization role, applied when the exchange runs (next row). | | Cloud exchange | After OAuth sign-in, DousenControl issues a short-lived, Ed25519-signed exchange token. DousenCore accepts it at `POST` or `GET /portal/auth/exchange` (the portal) and `POST /api/auth/exchange` (Desktop). | The account is created on the first exchange. Cloud `owner` and `admin` become Admin and everyone else becomes Artist, unless an admin created the account first with Invite User. | A user who belongs to more than one cloud organization sees a studio picker before reaching a specific instance, both in the interactive login and in the OAuth flow. ## Which role wins The role you set in Dousen always wins over a role from a directory or the cloud. A directory group or a DousenControl role only sets the starting role when Dousen first creates the account, and no later sign-in changes it. - LDAP: group membership decides the role only on the first sign-in, and not at all if an admin created the account first with Invite User. Removing someone from the admin group later doesn’t remove their Admin role. If Dousen has no user search base, it can’t read groups, so everyone starts as an Artist. See Directory sign-in. - Cloud: the DousenControl role applies only when the exchange creates a new account. An account invited from the Users page keeps the role the admin chose. To change a role afterward, use the role selector on the Users page. Disabling an account in your directory blocks new sign-ins, but DousenDesktop sessions that already exist keep refreshing until the refresh token expires. To end them, also Deactivate the user in Dousen. Dousen reads a user’s role from the database on every request, so a demoted admin loses admin access immediately. ## Sessions, tokens, and single-device enforcement On a DousenCore instance, the access token is a JWT that lasts 15 minutes. The refresh token is an opaque value that lasts 30 days and rotates on every use: refreshing revokes the old refresh token and issues a new pair. DousenDesktop refreshes automatically when it gets a 401. Single-device enforcement: a refresh token can carry a `device_id`. If a refresh or heartbeat arrives with a different `device_id` from the one stored for that session, the server answers 409 Conflict with `"session active on another device"`, and the app shows that message. So signing in on another machine stops the first session from refreshing. ## Cloud organizations and studios (DousenControl) DousenControl manages organization membership, separately from any DousenCore instance. | Role | Can do | |---|---| | `owner` | The organization’s creator. Has the same invite, billing, and license permissions as `admin`. | | `admin` | Manage invites, billing and checkout, and the organization’s license. | | `member` | Belongs to the organization, with no invite, billing, or license access. | Owners and admins invite people from the organization dashboard, or from a studio’s Invite User button (see Invites on a cloud studio). An admin never sets the invitee’s password. | Action | Endpoint | |---|---| | Send an invite | POST /api/orgs/:id/invites (owner or admin) | | List pending invites | GET /api/orgs/:id/invites (owner or admin) | | Accept an invite | POST /api/invites/accept (public, because the invitee isn’t a user yet) | DousenControl checks the seat limit before it creates an invite. An invite expires after 7 days. Its role can only be `admin` or `member`, because nobody becomes an `owner` by invite. The invitee sets their own password when accepting, at least 8 characters long. The seat check and the insert happen together, so two simultaneous accepts can’t oversubscribe a seat-limited organization. ### Cloud plans and seat limits | Plan | Default seats | |---|---| | trial | 5 | | free | 5 | | starter | 25 | | pro | 100 | | enterprise | 500 | A new subscription starts with these seat counts. The quantity Stripe reports for a purchase later replaces the number, and an admin can set an override. A trial lasts 14 days, then the organization moves to the permanent free plan. Each DousenCore instance reports its current user count to DousenControl in a daily heartbeat. If the count is over the seat limit for three consecutive heartbeats, DousenControl suspends the organization (further heartbeats get a 403) and emails the owner. A later heartbeat that’s back under the limit reactivates it. Only a seat overage triggers this suspension. A subscription that’s only `past_due` on payment isn’t suspended for that reason. ## Auth endpoint reference ### DousenCore (per studio instance) | Endpoint | Purpose | |---|---| | POST /api/auth/login | Local-account login. Returns a JWT access and refresh pair. | | POST /api/auth/refresh | Exchanges a refresh token for a new access and refresh pair (rotates on use). | | POST /api/auth/heartbeat | Device-session heartbeat. Returns 409 if another device now owns the session. | | POST /api/auth/exchange | Accepts a DousenControl exchange token and returns a session (used by Desktop). | | GET/POST /portal/auth/exchange | Accepts a DousenControl exchange token and starts a portal session. | | GET/POST /portal/login | Browser login form. | | POST /portal/logout | Clears the session cookies. | | GET/POST /portal/forgot-password | Self-service reset request. | | GET/POST /portal/reset-password | Self-service reset completion, and the page invite links open. | | GET /portal/users, POST /portal/users | List users, and invite a user (Admin). | | PUT /portal/users/:id/role | Change a user’s role (Admin). | | POST /portal/users/:id/send-reset | Send a password-reset email to a user (Admin). | | POST /portal/users/:id/deactivate | Deactivate a user (Admin). | | POST /portal/users/:id/reactivate | Reactivate a deactivated user, if a seat is free (Admin). | | POST /portal/users/:id/resend-invite | Send a pending invite again with a new link (Admin). | | POST /portal/users/:id/remove-pending | Cancel and delete a pending invite (Admin). Returns 409 for any other user. | | GET /portal/account, POST /portal/account/* | Self-service profile, password change, and session revocation, for any signed-in role. | ### DousenControl (cloud) | Endpoint | Purpose | |---|---| | POST /api/auth/login | Organization login. Returns a `choose_org` list instead of a token if the user belongs to two or more organizations. | | GET /oauth/authorize | Shows the browser login form for the Desktop PKCE flow. | | POST /oauth/authorize/submit | Checks the password, shows the studio picker if needed, and issues a short-lived auth code. | | POST /oauth/token | PKCE exchange. Checks the code verifier and issues the DousenCore-bound exchange token. | | POST /api/orgs/:id/invites, GET /api/orgs/:id/invites | Send and list invites (owner or admin). | | POST /api/invites/accept | Public. The invitee sets their own password. | Previous ← Loading studio tools Next Self-hosted install → ## Asset validation — Dousen URL: https://dousen.io/docs/validation.html Summary: How validators check assets in the DCC before export, how admins configure rules, and what each built-in rule checks. Updated October 2026 Describes how validators check assets in the DCC before export, how project admins configure the rules, and what each built-in rule checks. Validators catch problems before the file reaches Perforce or Unreal, such as a name that breaks the convention, a mesh that isn’t watertight, or a vertex skinned to too many bones. The Unreal plugin also checks asset names on import. ## Enable and test a rule (project admin) - Sign in to the web portal as an Admin. Click Projects, select your project, and click Validators. - In the tree, select Global, an asset type such as Static Mesh, or a taxonomy node. Each rule is tagged inherited, overridden here or added here, and an inherited rule also shows the node it comes from. - To add a rule, choose it from + add rule…. The validator reference shows which DCCs and asset types it covers. Use the toggle to turn the rule on or off, set the severity to error (blocks publishing) or warning (advisory), and enter its parameters. Editing an inherited rule creates an override at this node. To undo a change, click Reset on an overridden rule or Remove on a rule added here. - The editor saves each change as you make it, so there is no Save button. To check a change, select another node and then select this one again. - In the DCC, collect one valid and one invalid test instance for that node. The DCC caches conventions for up to five minutes, so wait or relaunch it, then click Validate. - Check that the invalid instance shows the message you expect and, for an error, can’t be published. Check that the valid instance still passes. If the project’s conventions are a Lua script, the tree is read-only. Change the rules in the script instead. See Authoring in Lua. ## Resolve a validation failure (artist) - Check only the instances you want to publish, and click Validate. - Expand the failing rule to see the affected instance and its message. If the result lists objects, click Select Invalid to select them in the scene. - If the rule has a Repair button, save your work and click it. Otherwise, fix the source by hand. - After you change the scene’s structure, click Reset to collect again, then validate again. Before you publish, make sure no blocking error or destination conflict remains. - If a project rule seems wrong, send the project admin the rule name, the message, the asset type and tags, and an example. In Blender’s Dousen panel, the buttons are Run Validation, Fix and Publish Checked Instances. See the worked example. ## Validator fields Every validator, built-in or custom, is a Python class with these fields and a `validate()` method that performs the check: | Field | Meaning | |---|---| | `rule_id` | A stable, dotted identifier grouped by area, such as `mesh.watertight`, `naming.convention` or `texture.max_resolution`. A convention uses it to turn the rule on. | | `name` | A readable name shown in the portal’s rule picker and in the DCC’s results list. | | `category` | Groups rules in the picker, and decides whether the Nanite / NonNanite gate applies. Examples are `Mesh`, `Rig` and `Nanite`. | | `hosts` | The DCCs that load the validator, such as `["blender"]`. `["any"]` loads it in every host. | | `severity` | What a failure means by default. error blocks the export. warning is advisory, and the artist can continue. A convention can override this for a project. | | `enabled` | Whether the rule is on by default. Some stricter or studio-specific rules ship turned off. | | `asset_types` | The asset types the rule applies to: `static_mesh`, `skeletal_mesh`, `animation_sequence`, `texture`, `hda` or `vat`. An empty list means any type. | | `params` | Typed values that admins can edit. Each is `{key, type, default, label}`, where type is int, float, bool, string or list. Examples are `max_tris = 50000` and `target_fps = 30`. | The check returns whether it passed, a message such as "Exceeds limit of 50,000 tris", the affected objects, and an optional fix function. See Writing a custom validator. The defaults on this page are the baseline. A project’s conventions can turn on a rule that is off by default, change a warning to an error, or tighten a parameter. ## Where rules come from and how they are scoped Validators are stored in the project’s naming-conventions document. You can attach a rule at three levels, and each applies to everything below it. For the entry format, see Validator entries. - Global applies to every asset in the project. - Asset type applies to every asset of one type. - Taxonomy node applies to one node in the taxonomy tree, at any depth, and everything beneath it. A deeper level overrides matching parameters from a shallower one, so a node can set a stricter texture limit for hero props than the global rule does. DousenCore stores each node’s effective rules in the compiled conventions, and a DCC uses the rules of the deepest matching node. Texture size limits are validator rules (`texture.max_resolution` and `texture.resolution_power_of_2`), so you set them on the Validators tab. ## The validator catalog The catalog is the list of rules that the portal’s rule picker offers. It has two layers: - A compiled baseline built into DousenCore, with naming, mesh, UV, scene, material, rig, animation, texture, HDA and VAT rules. It’s the fallback when a tenant hasn’t reported anything. - A layer reported by the DCC addons. On startup, each addon (Blender, Maya, 3ds Max, Houdini, Substance Painter and Substance Designer) sends DousenCore the list of validator classes it has registered, including custom plugins from `validators.extra_paths`. Core accepts the report only from an Admin session, so an addon started by any other user skips it. DousenCore merges the two layers for each tenant. A rule that appears only in the report is added to the catalog, with typed parameter fields in the rule picker. For a rule in both layers, Core keeps the baseline’s name, category, default severity and default state, and uses the report only to fill in parameters and asset types that the baseline leaves empty. When a DCC can’t reach the compiled conventions, it falls back to the validator catalog if DousenCore still serves it, and otherwise to the default rules built into the addon. | Endpoint | Purpose | |---|---| | `GET /api/validator-catalog` | Returns the merged catalog (baseline plus reported rules) with each rule’s parameters. The portal’s rule picker uses it. Any signed-in user can call it. | | `POST /api/validator-catalog` | A DCC addon reports its rule list for the tenant. The addon must be running in an Admin session. Other users get a 403. | ## Validator reference The built-in rules, by category. Default shows the default severity and whether the rule is on, and Parameters shows the baseline defaults. The Nanite, NonNanite and host-specific rules take their defaults from the addons, and the rest from DousenCore’s baseline catalog. ### Naming Every DCC reports these rules, which check names against the project’s compiled conventions. In Substance Painter, Substance Designer and Houdini, they check texture set, graph and HDA names. In those three, `naming.convention` checks only the prefix (Designer uses the `material` prefix, default `M_`, on graph names), and `naming.no_special_chars` doesn’t allow `-`. Houdini also allows `.` and `:`. | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `naming.convention` | error · on | any | — | Names start with the asset type’s prefix from the project convention (for example `SM_` for a static mesh), and the export name meets the convention’s pattern and length rules. Fails if the scene is unsaved, or if the file name still contains an unresolved `{placeholder}`. | | `naming.no_special_chars` | error · on | any | — | The file name and object names contain only letters, digits, `_` and `-`. Maya also allows `|` and `:`. | ### Mesh: general hygiene These geometry checks apply to every pipeline. The triangle limit is a general upper bound. The Nanite + Lumen — Static preset raises it to 2,000,000, and Nanite + Lumen — Foliage turns it off. Both rely on `nonnanite.max_triangles` for meshes without Nanite. | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `mesh.poly_count` | error · on | static_mesh, skeletal_mesh | `max_tris = 50000` | Each mesh has at most `max_tris` triangles. | | `mesh.no_ngons` | warning · off | static_mesh, skeletal_mesh | — | No faces with five or more sides. | | `mesh.no_zero_area` | error · on | static_mesh, skeletal_mesh | — | No faces with zero area. | | `mesh.no_nonmanifold` | error · on | static_mesh, skeletal_mesh | — | No non-manifold geometry, such as an edge shared by more than two faces. In Blender, open boundary edges also count, so an open mesh fails this rule. | ### Nanite: dynamic pipeline For meshes that use Nanite and Lumen. Nanite needs no authored LODs, but open edges, flipped normals, floating geometry and sliver triangles cause visible problems. These rules run only when the asset’s materials allow Nanite (see the Nanite gate). `uvs.min_coverage` belongs to this category even though its ID starts with `uvs.`. | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `mesh.watertight` | error · on | static_mesh | — | Every edge borders exactly two faces, so there are no open boundary edges. Nanite renders holes as missing triangles, and Lumen leaks light through gaps. | | `mesh.consistent_normals` | error · on | static_mesh, skeletal_mesh | — | No flipped or inconsistently wound faces, detected from edge winding. Flipped faces show up as pink in the Nanite viewport. | | `mesh.no_sliver_triangles` | warning · on | static_mesh, skeletal_mesh | `min_angle_deg = 5.0` | No triangle has a corner angle smaller than `min_angle_deg`. | | `mesh.no_loose_geometry` | error · on | static_mesh, skeletal_mesh | — | No loose vertices or wire edges that aren’t part of a face. Nanite can’t cluster them. | | `nanite.min_triangles` | warning · on | static_mesh | `min_tris = 1000` | Each mesh has at least `min_tris` triangles, so Nanite’s fixed per-mesh cost is worth paying. Below that, a traditional mesh is cheaper. | | `nanite.tri_vert_ratio` | warning · on | static_mesh | `max_vert_ratio = 0.6` | The ratio of vertices to triangles stays at or below `max_vert_ratio`. Extra vertices point to UV or normal seams that split geometry and hurt Nanite clustering. | | `uvs.min_coverage` | warning · on | static_mesh | `min_coverage = 0.65` | UV0 islands fill at least `min_coverage` of the 0–1 space, which keeps texel density efficient. A mesh with no UVs fails. | ### NonNanite: traditional pipeline These rules run instead of the Nanite rules when the asset’s materials don’t allow Nanite. They cover a traditional mesh with authored LODs and a baked lightmap. | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `nonnanite.max_triangles` | warning · on | static_mesh | `max_tris = 60000` | A triangle budget for meshes without Nanite, which cost more per triangle than Nanite meshes. Its default (60,000) is tighter than `mesh.poly_count` only when a preset or node raises `mesh.poly_count`, as Nanite + Lumen — Static does. | | `nonnanite.lod_chain` | warning · on | static_mesh | `min_lods = 1`, `tris_threshold = 20000` | A mesh with more than `tris_threshold` triangles has at least `min_lods` authored LODs, detected by name: `_LOD1`, `_LOD2` and so on. Meshes below the threshold need no LODs. | | `nonnanite.lightmap_uvs` | warning · on | static_mesh | — | The mesh has a second UV channel (UV1) for the baked lightmap. | | `nonnanite.max_bounds_ratio` | warning · on | static_mesh | `max_extent = 50` (m), `dense_tris = 100000` | Flags a mesh only when it is both large (its bounding-box diagonal is over `max_extent`, converted to meters whatever the scene units) and dense (over `dense_tris` triangles). Only that combination culls poorly without Nanite. | ### UVs | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `uvs.in_range` | warning · off | static_mesh, skeletal_mesh | — | UV coordinates stay within the 0–1 tile. | | `uvs.no_overlap_lightmap` | warning · on | static_mesh | — | No overlapping UVs in the lightmap channel. Overlaps bake as light bleed. | ### Scene | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `scene.transforms_applied` | error · on | static_mesh, skeletal_mesh | — | Scale is 1 and rotation is 0 on every mesh object. Blender and Maya offer an automatic fix that applies rotation and scale. | | `scene.no_hidden_objects` | warning · on | static_mesh, skeletal_mesh, animation_sequence | — | No mesh objects are hidden. Blender checks viewport and render visibility. Maya checks the visibility attribute. | | `scene.single_root_skeletal` | error · off | skeletal_mesh | — | A skeleton has a single root bone (a single root joint in Maya). | | `scene.no_loose_vertices` | error · on | static_mesh, skeletal_mesh | — | No vertices that aren’t connected to an edge. | ### Materials | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `materials.no_missing_slots` | error · on | static_mesh, skeletal_mesh | — | No empty or unlinked material slots on a mesh. | | `materials.expected_count` | warning · off | static_mesh, skeletal_mesh | `max_materials = 3` | No mesh has more than `max_materials` materials. See the note below this table. | | `materials.no_empty_texture_sets` | warning · on | texture | — | Every texture set has at least one layer (Substance Painter). | Max materials (`max_materials`) is an upper bound, and it defaults to 3 in Blender and Maya if unset. A project that still sets the older `expected_count` parameter keeps the exact-match behavior: each mesh must have exactly that many materials. ### Rig | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `rig.bone_naming` | warning · on | skeletal_mesh | `pattern = ^[a-z][a-z0-9_]*(\.[LR]|_[lr])?$` | Bone names match the regular expression: lowercase, with an optional left or right suffix. | | `rig.hierarchy` | error · on | skeletal_mesh | `check_symmetry = false` | The skeleton has a single root bone. When `check_symmetry` is on, every left bone needs a matching right bone. | | `rig.bone_count` | warning · on | skeletal_mesh | `max_bones = 256` | The skeleton has at most `max_bones` bones. | | `rig.max_influences` | error · on | skeletal_mesh | `max_influences = 4` | No vertex is skinned to more than `max_influences` bones. | | `rig.unweighted_vertices` | error · on | skeletal_mesh | — | Every vertex has at least one skin weight. | | `rig.root_at_origin` | error · on | skeletal_mesh | — | The root bone is at the world origin. | | `rig.bind_pose` | warning · off | skeletal_mesh | — | The skeleton is in its bind pose, with no leftover rotations. In Blender, only armatures set to Rest Position are checked. | | `rig.no_negative_scale` | error · on | skeletal_mesh | — | No bone has negative scale, which breaks in the engine. | ### Animation | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `anim.frame_range` | error · on | animation_sequence | — | The clip has keyframes and a valid frame range. | | `anim.fps_match` | error · on | animation_sequence | `target_fps = 30` | The scene frame rate equals `target_fps`. | | `anim.root_motion` | warning · off | animation_sequence | `expect_stationary = false`, `root_bone = root` | The root bone moves only when it should. Flags a moving root when `expect_stationary` is on, and a stationary root when it is off. | | `anim.no_keys_on_frame_zero` | warning · on | animation_sequence | — | No keyframes on frame 0. Unreal expects frame 1 or later. | | `anim.no_scale_keys` | warning · on | animation_sequence | `allow_root_scale = false`, `root_bone = root` | No scale keyframes on bones. When `allow_root_scale` is on, the root bone may have them. | | `anim.bone_count_match` | error · off | animation_sequence | `expected_bone_count = 0` | The skeleton has exactly `expected_bone_count` bones. A value of 0 means any count, so the rule passes. Set the real count to check it. | ### Textures | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `texture.resolution_power_of_2` | error · on | texture | — | The width and height of each texture set are powers of two. | | `texture.max_resolution` | warning · on | texture | `max_resolution = 4096` | The width and height of each texture set are at most `max_resolution`. | | `texture.channel_completeness` | error · on | texture | `required_channels = [BaseColor, Normal, Roughness]` | Each texture set has every channel in `required_channels`. | | `texture.channel_gamma` | error · on | texture | — | Color channels use sRGB, and data channels such as Normal and Roughness use Linear. The check also fails if the Painter version can’t report channel color spaces. | ### Houdini: HDA and VAT | Rule | Default | Applies to | Parameters | Checks | |---|---|---|---|---| | `hda.has_definition` | error · on | hda | — | Each selected node is an HDA instance with a definition. Fails if no node is selected. | | `hda.version_set` | warning · on | hda | — | The HDA has a version string. | | `hda.has_description` | warning · on | hda | — | The HDA has a label that differs from its type name. | | `vat.resolution_power_of_2` | error · on | vat | — | The VAT texture resolution parameters (`posmap_res`, `normalmap_res` and `vm_picture_res`) are powers of two. | | `vat.output_files_exist` | error · on | vat | `expected_outputs = [posmap, normalmap, geo_output]` | Each parameter in `expected_outputs` exists on the node and has a path set. The check doesn’t test whether the file is on disk. | ### Host-specific rules Some addons have checks of their own that aren’t in the baseline. They report themselves to the catalog on startup like a custom plugin, together with the DCCs that implement them. The rule picker lists these rules for every node and adds the hosts to the name, for example `(blender only)`. The rule’s detail shows `hosts:` followed by the DCCs. Only a host that implements the rule runs it, and a DCC that doesn’t implement it skips the rule without a warning. If no Desktop has reported hosts yet, the catalog has none to show, and a DCC without a validator for the rule shows the warning described in DCC coverage. Only Designer’s two resolution rules (`graph.resolution_power_of_2` and its `texture.resolution_power_of_2` alias) declare parameters, so the Textures rule can show Max resolution (px) and Require square output fields that only Designer uses. The other host-specific rules have no input fields in the portal. 3ds Max | Rule | Default | Parameters | Checks | |---|---|---|---| | `scene.units` | error · on | `unit_type = 5` | The scene units match `unit_type`. The default, 5, is centimeters. | | `scene.frame_rate` | error · on | `fps = 24` | The scene frame rate equals `fps`. | | `scene.no_unused_layers` | error · on | — | No empty layers other than layer 0. | | `rig.frozen_transforms` | error · on | `tolerance = 0.0001` | Every mesh has its position at zero and its scale at 1, within `tolerance`. If it fails, reset the transform before you export. | | `rig.no_bone_scale` | error · on | `tolerance = 0.0001` | No bone or Biped object has non-uniform scale. | | `animation.range` | error · on | `start_frame`, `end_frame` | The animation range starts and ends on the frames you set. The check passes if you set neither. | | `animation.no_redundant_keys` | error · on | `tolerance = 0.00001` | No key repeats the value of the keys on either side of it. | | `uvs.has_uvs` | error · on | — | Every mesh has UV channel 1. | | `uvs.no_overlapping` | error · on | `channel = 2` | No two faces on `channel`, the lightmap channel by default, share the same UV vertices. This is a duplicate-face check, not a full overlap test. | | `materials.naming` | error · on | `prefix = M_` | Every material name starts with `prefix`. | | `materials.no_missing` | error · on | — | No mesh is missing a material or uses a default material. | Substance Designer | Rule | Default | Parameters | Checks | |---|---|---|---| | `graph.output_completeness` | error · on | `required_outputs = [BaseColor, Normal, Roughness]` | Every graph has an output node for each name in `required_outputs`. | | `graph.resolution_power_of_2` | error · on | `max_resolution = 4096`, `require_square = true` | Each graph’s output size is square (when `require_square` is on) and no larger than `max_resolution`. It doesn’t test for a power of two, because Designer stores sizes as power-of-two exponents. Designer reports the same check as `texture.resolution_power_of_2` too. | | `graph.no_unconnected_nodes` | warning · on | — | No node is disconnected from the graph, with no input or output connections. | ## DCC coverage Blender, Maya and 3ds Max cover mesh authoring, and the other DCCs cover their own asset types. Every DCC reports the Naming rules. | Category | Blender | Maya | 3ds Max | Painter | Designer | Houdini | |---|---|---|---|---|---|---| | Naming | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Mesh hygiene | ✓ | ✓ | ✓ | — | — | — | | Nanite | ✓ | ✓ | ✓ | — | — | — | | NonNanite | ✓ | ✓ | ✓ | — | — | — | | UVs | ✓ | ✓ | ✓* | — | — | — | | Scene | ✓ | ✓ | ✓* | — | — | — | | Materials | ✓ | ✓ | ✓* | ✓ | — | — | | Rig | ✓ | ✓ | ✓* | — | — | — | | Animation | ✓ | ✓ | ✓* | — | — | — | | Textures | — | — | — | ✓ | — | — | | Graph | — | — | — | — | ✓ | — | | HDA / VAT | — | — | — | — | — | ✓ | 3ds Max uses the same rule IDs as Blender and Maya for Naming, Mesh hygiene, Nanite and NonNanite, and also for `scene.transforms_applied`, `uvs.min_coverage`, `uvs.no_overlap_lightmap` and `materials.no_missing_slots`. In the categories marked ✓*, it covers the rest with its own host-specific rules. For example, it checks the frame rate with `scene.frame_rate` instead of `anim.fps_match`, and it has no `rig.bone_count` rule. If a project turns on a rule that no DCC has a validator for, or before Desktop has reported which DCCs implement it, a DCC without a validator shows this warning: "No validator plugin found for rule 'rule id' on host 'host' — rule was skipped, not run." ### The Nanite / NonNanite gate Only one of the Nanite and NonNanite categories runs for each asset. Dousen picks it from the mesh’s material assignments in the project’s material catalog: - If every assigned material resolves to a catalog entry and allows Nanite, the Nanite rules run. - If every assigned material resolves and any of them doesn’t allow Nanite, the NonNanite rules run. - If the mesh has no assignment, or any assignment doesn’t resolve to a catalog entry, the Nanite rules run, so existing scenes keep running the checks they always ran. When Unreal imports a static mesh with a material assignment, it sets the mesh’s `NaniteSettings.bEnabled` from the same material lookup, so in the common case the export checks match the mesh’s Nanite setting. An unresolved assignment, or a geometry profile with `nanite: false`, can make them differ. For the import rules, see How the import sets Nanite. The Nanite / NonNanite gate is a preview feature. Which rules belong to each category, and how the gate handles edge cases such as unassigned or mixed materials, may change. ## Writing a custom validator To add your own checks, write a Python validator plugin and add its folder to the `validators.extra_paths` pipeline setting. Each entry can be: - a Perforce depot path, such as `//depot/tools/validators`, - a path relative to the source root (`DOUSEN_SOURCE_ROOT`), or - an absolute path. For local testing, you can also set `DOUSEN_VALIDATOR_PATHS` to absolute folders, separated by your platform’s path separator. A validator subclasses `ValidatorPlugin`, sets the same fields as the built-in rules, and implements `validate()`, so it gets the same kind of catalog entry, with typed parameter inputs in the rule picker. Register it with the `@register_plugin` decorator. Import everything from `dousen.validators`: | Import | Role | |---|---| | `ValidatorPlugin` | The base class you subclass. | | `register_plugin` | A decorator that adds your class to the registry, so Dousen discovers it and reports it to the catalog. | | `CheckResult` | The return type, an alias for `(bool, str, list[str], Callable | None)`. You can use it as the return annotation. | `validate(self, context, params)` must return a 4-tuple: - passed (`bool`): `True` if the check passed. `validate()` only reports pass or fail. The rule’s `severity` decides whether a failure blocks export (error) or is advisory (warning). - message (`str`): the explanation shown next to a failed result. Use `""` when the check passes. - affected_objects (`list[str]`): the names of the objects or faces that failed, so the panel can point at them. Use `[]` when the check passes. - fix_fn (`Callable | None`): an optional function, with no arguments, that fixes the problem. Return it to make the panel show a Repair button (Fix in Blender) that runs it and then validates again. Return `None` when there’s no safe automatic fix. Import DCC modules inside `validate()` and the fix function. Dousen imports your class in every host, but a host’s API (`bpy`, `bmesh`, `pymxs`, Maya `cmds`) exists only in the hosts you list in `hosts`. The first argument is the host’s context: `bpy.context` in Blender, and a dictionary in the other hosts. `params` holds the admin-configured parameters for this asset, so read your keys from it with defaults. PYTHON — a Blender custom validator, with an auto-fix`from dousen.validators import ValidatorPlugin, CheckResult, register_plugin @register_plugin class NoNgonsValidator(ValidatorPlugin): rule_id = "mesh.no_ngons_custom" # unique, dotted, namespaced name = "No ngon faces" # shown in the picker + results list category = "Mesh" # groups it in the picker hosts = ["blender"] # which DCCs load it; ["any"] = all severity = "warning" # default fail level; a convention may override enabled = True # on out of the box asset_types = ["static_mesh"] # [] = any type params = [ {"key": "max_sides", "type": "int", "default": 4, "label": "Max sides"}, ] def validate(self, bpy_context, params) -> CheckResult: import bmesh # DCC import stays inside validate() limit = int(params.get("max_sides", 4)) offenders = [] for obj in bpy_context.scene.objects: if obj.type != "MESH": continue bm = bmesh.new() bm.from_mesh(obj.data) ngons = sum(1 for f in bm.faces if len(f.verts) > limit) bm.free() if ngons: offenders.append(f"{obj.name} ({ngons} ngons)") if offenders: # An auto-fix: triangulate the offending meshes on demand. def _fix(): import bmesh for obj in bpy_context.scene.objects: if obj.type != "MESH": continue bm = bmesh.new() bm.from_mesh(obj.data) bmesh.ops.triangulate(bm, faces=bm.faces) bm.to_mesh(obj.data) bm.free() return False, f"{len(offenders)} mesh(es) contain ngons", offenders, _fix return True, "", [], None # passed: empty message, no offenders, no fix` A new rule appears in the portal’s rule picker after an Admin’s DCC has reported it. To give every artist the same checks with no per-machine setup, keep custom validators in Perforce. See Loading studio tools. ### Sharing one check across several DCCs Many rules use the same logic in every DCC and differ only in how they read the scene. The built-in validators split such rules into two classes, and yours can too: - A DCC-independent base class holds the metadata and implements `validate()` once: the comparison, the list of offenders, and the 4-tuple. It leaves one data method abstract. - A subclass for each DCC sets `hosts` and overrides only the data method, which returns raw measurements. This is why `mesh.poly_count` appears for Blender, Maya and 3ds Max in the coverage table. PYTHON — the base owns validate(); it calls an abstract hook`class BasePolyCountValidator(ValidatorPlugin): rule_id = "mesh.poly_count" # metadata lives on the base name = "Polygon count within project limit" category = "Mesh" severity = "error" asset_types = ["static_mesh", "skeletal_mesh"] def get_mesh_tri_counts(self, context, params): """DCC-specific hook — subclass returns [(name, tri_count), ...].""" raise NotImplementedError def validate(self, context, params) -> CheckResult: max_tris = int(params.get("max_tris", 50000)) offenders = [] for name, tris in self.get_mesh_tri_counts(context, params): # ← calls the hook if tris > max_tris: offenders.append(f"{name} ({tris:,} tris)") if offenders: return False, f"Exceeds limit of {max_tris:,} tris", offenders, None return True, "", [], None # ← the 4-tuple is assembled here, once` PYTHON — the Maya subclass overrides only the data hook`@register_plugin class MayaPolyCountValidator(BasePolyCountValidator): hosts = ["maya"] # the only metadata it adds def get_mesh_tri_counts(self, context, params): import maya.cmds as cmds # host import stays inside the hook return [ (t, cmds.polyEvaluate(t, triangle=True)) for t in _mesh_transforms() ] # returns raw data — NOT the 4-tuple` The Maya subclass doesn’t override `validate()`, so the runner calls `BasePolyCountValidator.validate()`. That method gets the raw counts from Maya’s `get_mesh_tri_counts()`, applies the `max_tris` comparison, and returns the tuple. Each base class defines the data method that its check needs: | Base class | Abstract data method | Subclass returns | |---|---|---| | `BasePolyCountValidator` | get_mesh_tri_counts | `[(name, tris)]` | | `BaseWatertightValidator` | get_mesh_boundary_edge_counts | `[(name, open_edge_count)]` | | `BaseConsistentNormalsValidator` | get_mesh_face_loops | `[(name, [face_vert_indices])]` | | `BaseNoSliverTrianglesValidator` | get_mesh_triangles | `[(name, [(p0, p1, p2)])]` | | `BaseNonNaniteMaxBoundsRatioValidator` | get_mesh_bounds_and_tris (and scene_unit_scale) | `[(name, bbox_min, bbox_max, tris)]` | For a check that runs in one host, subclass `ValidatorPlugin` directly and return the 4-tuple. If the same decision must run in two or more DCCs, use a base class with an abstract data method and a subclass for each host, so the hosts can’t drift apart. ## Validation history and project health The DCC addons record each validation run in DousenCore, under the email address of the signed-in user. Each instance you validate in the Publish tab logs its own run. DousenCore also stores runs that a studio tool posts to `POST /api/projects/:id/validators/log`. The portal shows the runs in three places: - Validation history lists the runs for the project, with the user, status and time. Click All, Pass, Warn or Error to filter by status. The list is paginated. - The per-asset history shows the 100 most recent rule results for one asset. To open it, click an asset’s name on the Assets tab. - The Health tab summarizes pass, warning and error trends and the top validator failures. The default period is seven days. The API accepts a different `period`, such as `24h`. | Endpoint | Purpose | |---|---| | `POST /api/projects/:id/validators/log` | Records the result of a validation run. The DCC addons call it, and DousenCore takes the user from the authentication token. | | `GET /api/projects/:id/health-summary` | Returns pass, warning and error trends, changelist activity and top offenders for a period. The free plan gets a 403. | ## Admins and artists - Admins choose which rules run, set severities and parameters, and add custom validators. Editing rules in the Validators tab, or through the separate override document at `PUT /api/projects/:id/validators` (which wins over the tree for every node that has the rule), requires the Admin role, and other users get a 403. The whole portal console, including validation history and the health dashboard, is Admin-only. See Roles on a studio instance. - Artists run the checks in the DCC at export time, fix errors, and review warnings. They can’t change which rules apply or their parameters. ## Worked example: an asset fails a validator This example uses Blender’s Dousen panel. Maya, 3ds Max, Substance Painter and Substance Designer work the same way with the Validate and Publish buttons on the Qt Publish tab. Houdini uses its Dousen: Validate shelf tool. - Run the validators. In the Dousen panel, check the instances you want to publish, open the Validation panel, and click Run Validation. The panel lists the rules by category, and you can expand a failing rule to see its message and affected objects. Say `naming.convention` fails as an error because a name doesn’t start with the project’s prefix. The status bar shows "Dousen validation: 1 error(s), 2 warning(s)". - Fix the error. If the rule has a Fix button, click it. Dousen applies the fix and runs the validation again. Otherwise, rename the object yourself and click Run Validation again. - Try to publish with an error. The Publish Checked Instances button in the Validation panel is disabled. If you click the button in the main Dousen panel instead, Blender shows "Fix validation errors before publishing", and nothing is exported or published. - Publish with only warnings. Warnings don’t block publishing, but you have to confirm them. When only warnings remain (say, a `nonnanite.max_triangles` warning), Publish Checked Instances opens a dialog with the option Publish despite validation warnings. Turn it on to publish anyway, or cancel and fix the warnings first. If you publish without the option, Blender shows "Review validation warnings before publishing". On the Qt Publish tab, a dialog asks "N warning(s) found. Publish anyway?" instead. Previous ← Naming conventions Next Materials and textures →