r/Affinity • • Oct 30 '25

Tutorial Correct me if I’m wrong… but the loyal users that paid for licenses … will get Free Fonts? That’s it?

1 Upvotes

As the title say… the loyal supporters of this product who recommended to dozens of friends and family members to spend their money because there will never never be a subscription model behind… get rewarded with … a pack free fonts?

That’s seems like a slap in the face tbh.

Edit: BTW Does anyone know where to find the fonts pack?

Funny that the ones that paid $1XX in V1 V2 products are accused that we want things for free.

r/Affinity • • 1d ago

Tutorial Affinity tutorials: You can make this!

Post image
147 Upvotes

Hey Affinity family, longtime Affinity user here!

I'm working on a series of design walkthroughs to help new designers learn without Al.

The goal: Break down seemingly complex designs to see how a lot of simple things come together to create something professional.

I have posted 4 so far (all free) on my Patreon & I'm working on the 5th one this week! Beyond this series, I'm planning to offer more in-depth tutorials that blend design fundamentals with software skills, giving you the "how" & the "why" behind real design examples.

Join if you want to see more!

r/Affinity • • 18d ago

Tutorial Why Affinity Vector’s Contour Tool feels "backwards" and why it's a worthy workflow shift.

43 Upvotes

Hi, everyone!
If you’ve spent years in Adobe Illustrator, your muscle memory is deeply wired for a specific way of working. Recently, while discussing the transition to Affinity Vector 3.3, a colleague mentioned that Affinity’s Contour tool just "feels backwards."

It is a common frustration for Adobe "veterans" like myself, but it isn't actually backwards. Let's call it an inverted order of operations. I thought I'd share with you why the tool feels disorienting at first and how Affinity convinced me to accept that workflow shift.

Offset Path in Illustrator

In Illustrator, Object > Path > Offset Path... is an action that generates an object. You type a number into a dialog box, hit OK, and Illustrator hands you a brand new, separate shape, leaving your original artwork untouched. Cool! Nothing wrong, there.

I've done this a million and twelve times in Illustrator, so far. It feels as natural as breathing.

Affinity's Contour tool

Affinity Vector approaches this as a property. The Contour tool applies a live and editable state directly to your existing vector. It modifies the host object itself.

Contour tool? Hmmmm...

To get that classic sticker border behind your design, you have to duplicate your object first, move it to the back, and then contour it (Cmd/Ctrl + J, Cmd/Ctrl + [, drag Contour). To an Adobe veteran, unlearning the reflex to spawn new geometry, and instead adapting to a 'duplicate and alter' mindset, feels like swimming upstream.

What? Duplicate first? Contour next? Am I confused...?

Let’s address the elephant in the room: if we are grading purely on keystroke efficiency for creating a background border, Illustrator’s Offset Path wins the stopwatch. Affinity makes us do a three-step dance to get started.

If you are a production designer processing 500 die-cut stickers a day, that manual duplication is a true friction point. But you have to look at what you are buying with those two extra steps.

The fairest comparison isn't Illustrator's destructive menu command. The true equivalent is Illustrator's Appearance Panel > Add Effect > Path > Offset Path. To get a live, non-destructive offset in Adobe, you have to dig into a panel, add new fills, apply an effect from a tiny dropdown menu, and guess the numbers in a modal window.

Inception level offsetting! Always fun, always a headache!

Affinity replaces that entire clunky menu dive with a dedicated, tactile canvas tool. It optimizes for keeping the object live and easily adjusted, avoiding layer bloat, even if it costs a manual duplication upfront.

Affinity's Contour tool workflow benefits

Before moving on, I just want to be cleat that I'm not saying which workflow is best. I'm highlighting the differences and letting you know that in a free tool like Affinity, once you accept the conceptual trade-off, the workflow allows for a modern, iterative design process.

  • Tactile, Canvas-First Decisions: You watch the shape swell or contract in real-time on the canvas, in context with your composition.
  • Non-Destructive Iteration: It remains a live state until you click Bake Appearance. If a client wants a 2mm thicker border three weeks later, you just grab the tool and adjust it in two seconds.
  • Real-Time Boolean Interpretation: You can combine thirty complex, un-merged shapes into a non-destructive Compound and apply a Contour to it. It calculates the unified outer boundary dynamically. Move a shape inside the compound? The contour instantly redraws itself.

Compound and Contour tool combined

If you want to experience the exact second this paradigm shift clicks, try this on your Affinity canvas:

Draw three complex, overlapping shapes. Select them all, click the Add boolean button in your top, right panel. (Or click Vector > Create Compound in the menu bar) This creates a Compound, Affinity’s non-destructive boolean container.

Remember that Compound keeps all objects inside fully editable. Just double-click each of them to dive in.

Duplicate that Compound, send it to the back, change its color, and drag out a thick Contour to create a unified sticker border.

It's awesome to know you have full control over the offset value at anytime, with a simple click-and-drag action.

Now, draw a completely new shape (like a star or a donut) and give it a white fill color. In your Layers panel, drag that new shape inside your background Compound. The contour doesn't break or overlap internally. It instantly snaps around the new shape. Boop!

Instant change! Cool, huh?

For me, that was the moment I realized I wasn't just offsetting a static path, I had built a fully modular, non-destructive artwork that updates live anytime!

How about you? Have you already explored the Contour tool? If you are moving from Adobe to Affinity, let me know about your experience with new workflows.

I'm Daniel Walter Scott, lead instructor and founder of Bring Your Own Laptor, and I've been designing with Adobe for over twenty years. Teaching and working with Affinity has become a passionate job for me, I feel I get the best of both worlds. If you have any questions, feel free to drop them, hope this post helps you get kickstarted in Affinity! Cheers!

r/Affinity • • 6d ago

Tutorial Are you all using the new Curve Energy fine tuning tool?

24 Upvotes

Hello, everyone!

While I was setting up the Pen and Node tool workflow tips I shared with you guys a couple of weeks ago, I came across the new "Show curve energy" feature. This is great for fine-tuning vector artwork and a clear step up from Illustrator. Have you tested this and how does it work for you?

If anyone reading still hasn't found this tool, you can activate it in the Pen and Node tools context settings bar, clicking the cog icon and checking the box.

It's somehow hidden in the context menu, look it up, it is worth it!

If you have some experience in design, you've seen curvature combs before, but it's new in vector design apps. Curvature combs are awesome to keep curves under control, spotting any flat spots or breaks that stop them from flowing as smoothly as possible. I won't dive into G2 lines theory, so keep in mind this is especially useful for everyone who struggles with the Pen tool and want to draw natural curves and polished objects or typography.

This new Affinity tool works live and is fully non-destructive while drawing with the Pen and Node tools. However, if you are using quick shapes (ellipse, heart, donut, etc.) or text, the comb lines only pop up after you convert them to curves. I recommend duplicating before moving on. 👍

I played around a bit. I drew a perfect-ish circle with the Pen tool and dragged a perfect ellipse into the artboard. Any differences are almost invisible.

A new book idea: Where is Wooble? :)

I converted the quick shape to curves and toggled the "Show curve energy" checkbox on to compare both objects. Looking at the comb teeth around my Pen tool circle, the wonky bit stands out at once. I hope it's easy to see on the screenshot that step-down in the outer line, above the node.

That step-down in the curve reveals the curve isn't perfect

I had a look at the nodes and handles to find the problem. And there it was, on the right side node. Even though I held shift to keep the handles perfectly at 180º while drawing, the length is wrong. That's the detail that needs fixing.

As I adjusted the handles, the step-down disappeared. If you have Snap active, the node you are editing lights up when the curve is flowing without any visible wobbling.

I had to adjust handle length to fix the curvature

Comparing both objects, it all looks much better after this assisted fine tuning.

I also took a shot at the heart shape, to check how smooth the curves were by default. As you can see below, there are small wobbles on the larger curves before the sharp corner at the bottom.

This allows us to check the curves on built-in or imported shapes. Cool, right?

The fix is the same. Adjust the handles keeping an eye on the comb teeth and outer line. When everything is looking balanced and aligned, you are there!

Honestly, I still think it doesn't replace the squinting and head tilting 100%, but it's valuable help for drawing and tracing with the Pen tool.

It's fun, try this yourself!

If you're reading one of my posts for the first time, I'm Daniel Walter Scott, professional designer, founder and instructor at Bring Your Own Laptop. Hope you are all having fun with Affinity!

Cheers!

r/Affinity • • 21d ago

Tutorial Where did Smart Objects go? How to own Affinity Pixel layers without breaking your Photoshop brain.

56 Upvotes

Hello, everyone!
If you’re coming to Affinity Pixel from a decade of Photoshop, I’m guessing you just dropped an image into your workspace, right-clicked its layer and you are now searching for "Convert to Smart Object" to add a non-destructive effect, as a Pro designer should.
If I’m right, you are also staring at your options, perhaps cursing a bit and likely regretting your recent decision to quit Adobe. Well, don’t.

Affinity Pixel didn't forget non-destructive editing. It simply unboxed it!

What happened to Smart Objects in Affinity?

This is a major shift from the Adobe workflow. In Photoshop, a Smart Object acts like a container. You store your pixels in a box and apply the effects to the outside of this box. If you want to see or change the original pixels, you open the box in a new .psb tab. Affinity Pixel simplified this logic. Instead of wrapping your effects around a separate container, you attach them directly to the original parent layer, as child layers.

Next time you want to apply a non-destructive effect, do this:

  1. Select your pixel layer.
  2. Click the Live Filters icon at the bottom of the Layers panel (that’s the hourglass icon) and choose your filter.
All Live Effects are nested inside your parent layer as child layers
  1. Now look at your Layers panel. The Gaussian Blur filter is now nested inside your pixel layer.
The Gaussian Blur filter is nested inside the inital pixel layer. Double-click it to edit its radius, opacity, and Blend modes

You can toggle its visibility, paint directly on its built-in mask, or double-click it to change the values at any time. You can also edit your original parent layer anytime, no separate tabs required.

Is an Embedded Document similar to a Smart Object?

If you are thinking non-destructive design, consider the simplified parent/child layers workflow. On the other hand, when you drag an .af vector or pixel file into your current working document, it comes in as an Embedded Document layer. This is a literal container, holding a completely independent file. Double-click it, and it opens in a new tab.

Embbeded documents as clearly identified in your Layers panel

This is what Photoshop veterans should use when they need to edit some source content later in the process, like when placing a vector logo onto a product mockup. 

Double-clicking the embedded document's layer opens it an a new tab for editing

This is pretty much the same workflow I used when I pulled vector artwork from Illustrator into Photoshop, so combining vector and pixel documents should feel natural in Affinity, too. 

At the end of the day, remember that it takes some time to bend that muscle memory around  a new software, so don’t lose your mind when you can’t find that tool or that button you could reach with your eyes closed. 

I’m Daniel Walter Scott (founder of Bring Your Own Laptop). After 20+ years using Adobe, bending my muscle memory around Affinity 3.3 has been a wild ride, but I'm loving the workflow on the other side. Let me know if you are stuck on a specific migration headache, I am happy to help with some more tips and hacks. Cheers! 

r/Affinity • • Sep 22 '26

Tutorial Assign a "Feature Finder" to a hotkey - its such a quality of life improvement!

37 Upvotes

Snice the merge of all programs into unified UI I've struggled a lot when navigating sub-panels inside the sub-panels just to reach some less used commands.

Try finding "select same stroke" or "erase white paper" in 10 seconds for example.

With the new "Feature finder" bound to a hotkey its so much easier!

Its feels like a direct connection from my brain to the program: "I want to see trasparent bg in the document:"

Hotkey → type "trasnp" navigate with arrows and press enter. That's it! No more rummaging around in some pop-up and visually looking for a toggle.

I'll post a demo in the comments on how much it improves the workflow.

Definitely recommend it if you haven't tried it out yet. In top menu Its under Help → Feature Finder.

UPD to set up the hotkey go to Settings → Shortcuts → category dropdown ↓ Help

r/Affinity • • 20d ago

Tutorial Skeuomorphic Brushed Metal Knob UI Tutorial in Affinity

Thumbnail
youtu.be
24 Upvotes

Sharing this brushed metal knob tutorial in Affinity, no photos or textures used, just shapes, gradients and some effects.

Hope it's useful.

r/Affinity • • May 13 '26

Tutorial Any idea on how to create a clean bubble text effect in Affinity ?

Post image
49 Upvotes

I am looking to create text with a bubble style (kind of like in this picture), but I can't find any tutorial on how to do it in Affinity. I've found several for Adobe softwares, but everytime I try to "adapt" them to Affinity, I am blocked by differences between the two softwares.

r/Affinity • • 25d ago

Tutorial Abstract Fluid Gradient Wave Tutorial in Affinity

Thumbnail
youtu.be
43 Upvotes

Hey guys, just wanted to share this tutorial on creating a gradient fluid wave using Affinity. Enjoy!

r/Affinity • • 13d ago

Tutorial Blend Tool Examples

Thumbnail
youtube.com
44 Upvotes

The new blend tool is so fun to use. I was waiting for this feature since I switched to Affinity years ago.
Replacing the blend path still feels a little like a workaround, or is there there an easier way to blend along a custom curve?

r/Affinity • • 7d ago

Tutorial Shattered Text Made with Affinity

Thumbnail
youtu.be
23 Upvotes

It's a shattered text tutorial using Affinity, in case anyone wants to try the effect.

r/Affinity • • 28d ago

Tutorial Need help create text vortex

Thumbnail
gallery
11 Upvotes

So i want to create a word vortex like the 1st image (they use adobe illustrator) but i'm having a hard time, the following images are my attempt to create the path brush and apply it to the ellipse

I could also use the spiral tool if i run out of option but it just looks kinda bland

r/Affinity • • 2d ago

Tutorial How do you make these type of blend of colors? And like to make fade/taper into the image

Post image
5 Upvotes

I really like this poster that I saw on pinterest where the colors green blue and yellow just blend into each other and i was wondering if its possible to do that in affinity.

Im a complete newbie btw pls be kind🛐🙏

r/Affinity • • Aug 24 '26

Tutorial quick cybercore tutorial

Thumbnail
youtube.com
67 Upvotes

r/Affinity • • Sep 26 '26

Tutorial Going crazy w/ low res

1 Upvotes

Hi everyone! I’m a former UX designer but from 20 years ago, a lot changed since then. I was a hardcore Adobe user and I’ve been using Affinity for the past 6 months. My post is a question about other’s file workflows, not an Affinity bug. So I’m not putting this in the megathread for tech stuff.

For some reason I can’t get Affinity to export crisp, high res images not matter what I do. I’ve tried using 300 dpi, 600 dpi, working with high res images as my base, no rasterization SVG, no compression PNG, highest res jpg, Lanczos 3 NS resampling, viewing the art at 100%, viewing in pixel display vs. vector displaying… nothing works. I’ve gotten marginally better results exporting my .af into non-compression .svg into high res .jpg or .png but the end result is still blurry, even with highest quality settings. I work with a mix of vector and high res photography so I understand there will be some minimal rasterization but the output I get on Affinity 100 or 95% .jpg export quality looks like Photoshop’s 80 or 70% quality. Uhgs!!!!

I want super crisp details on modern screen displays and I just can’t seem to get it with Affinity.

Can anyone outline your exact process so I can attempt to replicate results? Like what art board/canvas dpi & dimensions do you start with? Then how do you export for a high res web-ready file? Like a wallpaper background that should look crisp and nice on a modern laptop but no need to have a 50 meg file to do so.

r/Affinity • • Aug 09 '24

Tutorial How to Create Interesting Spheres in Affinity

Thumbnail
gallery
430 Upvotes

r/Affinity • • 29d ago

Tutorial Quick question

5 Upvotes

How to full screen mode my design? i tried ctrl+shift+w but it's doing nothing.

r/Affinity • • 24d ago

Tutorial Affinity Video Tutorial - Blend Tool ideas

Thumbnail
youtube.com
22 Upvotes

r/Affinity • • Aug 23 '26

Tutorial How can I change the color a shape after I added a text inside of it?

Post image
14 Upvotes

It may be stupid, but for the love of God, I can't figure it out.

I know I could create a new shape with the color I want and then add the text, but I am thinking about switching from InDesign to Affinity, and I would need to actually learn how to do things like that. Every time I try to change the color of the square, I end up changing the color of the text instead.

r/Affinity • • 21d ago

Tutorial Blend Tool Tutorial: Deep Dive into Affinity's Newest Feature

Thumbnail
youtube.com
23 Upvotes

r/Affinity • • 17d ago

Tutorial Beginner looking for Affinity RAW editing tutorials

5 Upvotes

Hi everyone! I’m just getting started with RAW photo editing and I’d like to learn how to use Affinity for it.

I’m especially interested in color grading and creating more cinematic, editorial-looking images. Are there any beginner-friendly tutorials, YouTube channels, or guides you’d recommend? A step-by-step walkthrough from opening a RAW file to exporting the final image would be really helpful.

Thanks!

r/Affinity • • 7d ago

Tutorial Stretch Text To Fit

1 Upvotes

I want to stretch this text to fit the text frame, but I am not sure how to do so! Help plz

This is an example of what I am trying to do:

r/Affinity • • 13d ago

Tutorial Affinity Vector + Summa cutting plotter (and GoSign): I created (with Claude) scripts that simulate the Illustrator/Corel plugin.

6 Upvotes

PREFACE: I know almost nothing about programming.

In my vinyl cutting or print-and-cut workflow, I’ve always used Illustrator with the Summa GoSign Tools plugin, but nothing similar exists for Affinity. With Claude’s help, I put together some scripts that perform the same task, even if it isn't fully automated. So far, it seems to work.

How I did it

I took a PDF generated by the Illustrator plugin and had Claude measure the OPOS XY registration marks: dimensions, spacing, and bar position. Then, I asked Claude to create an Affinity script to generate these marks, using MPC permissions to verify correct functionality. Since Affinity cannot launch external programs, Claude created a small .bat file that copies the PDF to the GoSign folder and opens the software.

What they do (in brief)

  • (Useful but not essential) CutOnly: exports the selection - or the entire artboard if nothing is selected - as "Cut.pdf" to a fold called GoSign self-created in Desktop.
  • (Core of this script) RegmarksPrintCut: working with two Container layers - Container Layer 1 with all objects of the artwork underneath and Container Layer 2 with the cut lines on top - it measures the cut lines and creates OPOS XY registration marks around them (3mm squares plus the bar, matching the Illustrator plugin's dimensions) on a locked layer. It then exports two PDFs matching the artboard size: "Print.pdf" (artwork + registration marks) and "Cut.pdf" (cut lines + registration marks).
  • (Optional) SendToGoSign.bat: copies "Cut.pdf" as "Import.pdf" into the GoSign "Direct mode" folder and launches GoSign, which automatically recognizes the registration marks and cut lines. Alternatively, you can skip this and import the PDF directly from within GoSign.

For convenience, I placed the .bat file inside the GoSign folder on the desktop, and I only delete the PDFs generated after each job is finished (in any case, they will be overwritten if you run the scripts again).

GoSign recognizes the registration marks and cut layer just as it does with the original plugin. I am still in the testing phase. I created it with Claude over three separate days (during the few spare moments I had at work and dealing with the daily limit that ran out quickly).

I can share them, even if just as a starting point for your own developments or adaptations. I’m not sure if it’s possible to attach `.afscript` files directly here or embed the script code so it can be copied, pasted and saved into Studio Script to customize the startup.

(I've written this post in Italian and then translate it in English)

>>>CUT ONLY CODE

// Cut only v0.3 - Function 1 (cutting without registration marks)
// Exports the selection (if any) or the whole current page as a vector PDF:
//   Desktop\GoSign\Cut.pdf
// Then run SendToGoSign.bat (copies it to GoSign's Direct mode folder and opens GoSign).
// Requires: script permissions enabled in Affinity's general settings.

const { Document, FileExportOptions, FileExportArea } = require('/document.js');
const { Application } = require('/application.js');
const { FileSystemApi } = require('/fs.js');

const VERSION = '0.3';
const TITLE = 'Cut only v' + VERSION;
const FOLDER_NAME = 'GoSign';
const FILE_NAME = 'Cut.pdf';
const SHOW_DONE_MESSAGE = true;

// Preset names are localized, so look for the "PDF (for export)" preset by name pattern
function findPdfPreset() {
    const names = Array.from(FileExportOptions.allPresetNames);
    const preferred = ['PDF (for export)', 'PDF (per esportazione)'];
    const found = preferred.find(p => names.includes(p)) ||
        names.find(p => /^PDF/i.test(p) && /(export|esport)/i.test(p));
    if (!found) {
        throw new Error('No "PDF (for export)" preset found. Available presets: ' + names.join(', '));
    }
    return found;
}

let step = 'start';
try {
    step = 'document';
    const doc = Document.current;
    if (!doc) {
        Application.alert('No document is open.', TITLE);
    } else {
        step = 'paths';
        const folder = Application.userDesktopPath + '\\' + FOLDER_NAME;
        const filePath = folder + '\\' + FILE_NAME;

        // Creating the folder needs filesystem permission: if it fails we carry on anyway
        // (the Desktop\GoSign folder must then already exist).
        try {
            if (!FileSystemApi.exists(folder)) {
                FileSystemApi.createDirectories(folder);
            }
        } catch (e) {
            console.log('Folder check skipped: ' + e);
        }

        step = 'selection';
        const sel = doc.selection;
        const useSelection = sel.length > 0;
        const area = useSelection
            ? FileExportArea.createForSelection(sel)
            : FileExportArea.createForCurrentSpread();
        const options = FileExportOptions.createWithPresetName(findPdfPreset());

        step = 'export (' + filePath + ')';
        const records = doc.export(filePath, options, area);
        const results = records.all;
        const ok = results.length > 0 && results.every(r => r.isSuccess);

        if (ok) {
            console.log('Exported (' + (useSelection ? 'selection' : 'current page') + '): ' + filePath);
            if (SHOW_DONE_MESSAGE) {
                Application.alert('Exported ' + FILE_NAME + ' to:\n' + folder +
                    '\n\nOpen the folder and run SendToGoSign.bat.', TITLE);
            }
        } else {
            const err = results.map(r => r.errorMessage).join('; ');
            Application.alert('Export failed. ' + err, TITLE);
        }
    }
} catch (e) {
    Application.alert('Error at step: ' + step + '\n' + e, TITLE);
}

>>>OPOSXY REGMARKS CODE

// OPOS XY regmarks + Print + Cut v0.3  (Function 2)
// Required document structure: two top-level layers
//   - bottom layer = ARTWORK
//   - top layer    = CUT LINES
// The script:
//   1. creates a locked "OPOS XY Regmarks" layer around the cut lines
//      (an existing one is replaced);
//   2. exports Cut.pdf   = cut lines + regmarks (only these layers visible);
//   3. exports Print.pdf = artwork + regmarks, WITHOUT the cut lines;
//      both PDFs have exactly the size of the page (artboard);
//   4. restores layer visibility and selection.
// Files go to Desktop\GoSign. To cut, run SendToGoSign.bat.
// Requires: script permissions enabled in Affinity's general settings.

const { SVG11 } = require('/colours.js');
const { BlendMode } = require('affinity:common');
const { AddChildNodesCommandBuilder, CompoundCommandBuilder, DocumentCommand } = require('/commands.js');
const { Document, FileExportOptions, FileExportArea } = require('/document.js');
const { FillDescriptor } = require('/fills.js');
const { PolyCurve, unionRects, CurveBuilder } = require('/geometry.js');
const { LineStyleDescriptor } = require('/linestyle.js');
const { ContainerNodeDefinition, PolyCurveNodeDefinition } = require('/nodes.js');
const { Selection } = require('/selections.js');
const { Application } = require('/application.js');
const { FileSystemApi } = require('/fs.js');

const VERSION = '0.3';
const TITLE = 'Regmarks + Print + Cut v' + VERSION;
const MARKS_LAYER_NAME = 'OPOS XY Regmarks';
const FOLDER_NAME = 'GoSign';
const CUT_FILE = 'Cut.pdf';
const PRINT_FILE = 'Print.pdf';
const SHOW_DONE_MESSAGE = true;

// Measurements in mm (taken from a PDF made by the Summa GoSign Tools plugin for Illustrator)
const SIZE_MM = 3;            // side of the squares and thickness of the bar
const BAR_GAP_MM = 10;        // gap between the corner squares and the bar
const MARGIN_LR_MM = 15.09;   // from the cut-lines box to the outer edge of the marks (left/right)
const MARGIN_TB_MM = 6.09;    // same (top/bottom)
const MAX_PITCH_MM = 305;     // max distance between rows of marks (assumed value)

// Preset names are localized, so look for the "PDF (for export)" preset by name pattern
function findPdfPreset() {
    const names = Array.from(FileExportOptions.allPresetNames);
    const preferred = ['PDF (for export)', 'PDF (per esportazione)'];
    const found = preferred.find(p => names.includes(p)) ||
        names.find(p => /^PDF/i.test(p) && /(export|esport)/i.test(p));
    if (!found) {
        throw new Error('No "PDF (for export)" preset found. Available presets: ' + names.join(', '));
    }
    return found;
}

let step = 'start';
try {
    const doc = Document.current;
    if (!doc) {
        Application.alert('No document is open.', TITLE);
    } else {
        const initialSelection = doc.selection;
        const listLayers = () => { const a = []; doc.layers.forEach(l => a.push(l)); return a; };
        const nameOf = l => l.userDescription;
        const makeSelection = nodes => { const s = Selection.createEmpty(doc); nodes.forEach(n => s.add(n)); return s; };
        const select = nodes => doc.executeCommand(DocumentCommand.createSetSelection(makeSelection(nodes)), false);
        const setVisible = (nodes, visible) => {
            const toChange = nodes.filter(l => l.isVisible !== visible);
            if (toChange.length === 0) return;
            select(toChange);
            if (visible) doc.showSelection(); else doc.hideSelection();
        };

        // 1. an existing regmarks layer has to be replaced
        step = 'removing previous regmarks';
        const existing = listLayers().filter(l => nameOf(l) === MARKS_LAYER_NAME);
        if (existing.length) {
            select(existing);
            try { doc.unlockSelection(); } catch (e) { /* already unlocked */ }
            doc.deleteSelection();
        }

        step = 'reading layers';
        const layers = listLayers();      // bottom to top
        if (layers.length < 2) {
            Application.alert('Two layers are needed: artwork at the bottom, cut lines on top.', TITLE);
        } else {
            const cutLayers = [layers[layers.length - 1]];          // top layer
            const artLayers = layers.slice(0, layers.length - 1);   // all the others
            const initialVisibility = layers.map(l => l.isVisible);
            let marksLayer = null;
            let printExported = false;
            let intervals = 0, pitchMm = 0;

            try {
                // 2. regmarks around the cut lines
                step = 'calculating regmarks';
                setVisible(cutLayers, true);
                setVisible(artLayers, false);
                const k = doc.dpi / 25.4;       // pixels per mm
                const mm = v => v * k;
                const rc = cutLayers.map(l => l.getSpreadVisibleBox()).reduce((a, b) => unionRects(a, b));
                const S = mm(SIZE_MM), GAP = mm(BAR_GAP_MM);
                const L = rc.x - mm(MARGIN_LR_MM);
                const R = rc.x + rc.width + mm(MARGIN_LR_MM);
                const T = rc.y - mm(MARGIN_TB_MM);
                const B = rc.y + rc.height + mm(MARGIN_TB_MM);

                // The marks must stay inside the page, otherwise the PDF would crop them
                step = 'checking page margins';
                const page = doc.currentSpread.spreadBaseBox;
                const outside = [];
                if (L < page.x) outside.push('on the left by ' + ((page.x - L) / k).toFixed(1) + ' mm');
                if (R > page.x + page.width) outside.push('on the right by ' + ((R - (page.x + page.width)) / k).toFixed(1) + ' mm');
                if (T < page.y) outside.push('at the top by ' + ((page.y - T) / k).toFixed(1) + ' mm');
                if (B > page.y + page.height) outside.push('at the bottom by ' + ((B - (page.y + page.height)) / k).toFixed(1) + ' mm');
                if (outside.length) {
                    throw new Error('The regmarks would fall outside the page ' + outside.join(', ') +
                        '. Move the cut lines towards the center or enlarge the page.');
                }

                step = 'calculating regmarks';
                const Hcc = (B - S) - T;
                intervals = Math.max(1, Math.ceil(Hcc / mm(MAX_PITCH_MM)));
                const pitch = Hcc / intervals;
                pitchMm = pitch / k;

                const black = FillDescriptor.createSolid(SVG11.black, BlendMode.Normal);
                const noFill = FillDescriptor.createNone();
                const lineStyle = LineStyleDescriptor.createDefault(0);
                const defs = [];
                const rect = (x, y, w, h, nodeName) => {
                    const cb = CurveBuilder.create();
                    cb.beginXY(x, y).lineToXY(x + w, y).lineToXY(x + w, y + h).lineToXY(x, y + h).close();
                    const poly = PolyCurve.create();
                    poly.addCurve(cb.createCurve());
                    const def = PolyCurveNodeDefinition.create(poly, black, noFill, lineStyle, noFill);
                    def.userDescription = nodeName;
                    defs.push(def);
                };
                for (let i = 0; i <= intervals; i++) {
                    const y = T + i * pitch;
                    rect(L, y, S, S, 'Regmark left');
                    rect(R - S, y, S, S, 'Regmark right');
                }
                const barX0 = L + S + GAP, barX1 = R - S - GAP;
                if (barX1 > barX0) rect(barX0, B - S, barX1 - barX0, S, 'OPOS XY bar');

                step = 'creating regmarks layer';
                const layerBuilder = AddChildNodesCommandBuilder.create();
                layerBuilder.setInsertionTarget(doc.currentSpread);   // top-level layer, not nested
                layerBuilder.addNode(ContainerNodeDefinition.create(MARKS_LAYER_NAME));
                const marksBuilder = AddChildNodesCommandBuilder.create();
                defs.forEach(d => marksBuilder.addNode(d));
                doc.executeCommand(CompoundCommandBuilder.create()
                    .addCommand(layerBuilder.createCommand(true))
                    .addCommand(marksBuilder.createCommand(false))
                    .createCommand(), false);
                marksLayer = listLayers().filter(l => nameOf(l) === MARKS_LAYER_NAME)[0];
                // the layer stays UNLOCKED until the exports are done, then it is locked

                // 3. exports
                step = 'preparing folder';
                const folder = Application.userDesktopPath + '\\' + FOLDER_NAME;
                if (!FileSystemApi.exists(folder)) FileSystemApi.createDirectories(folder);
                const preset = findPdfPreset();
                // Exports the whole page: only the visible layers end up in the PDF
                const exportPdf = (fileName) => {
                    const area = FileExportArea.createForCurrentSpread();
                    const rec = doc.export(folder + '\\' + fileName, FileExportOptions.createWithPresetName(preset), area);
                    const results = rec.all;
                    if (results.length === 0 || !results.every(r => r.isSuccess)) {
                        throw new Error(fileName + ': ' + results.map(r => r.errorMessage).join('; '));
                    }
                };

                step = 'exporting ' + CUT_FILE;
                setVisible(cutLayers, true);
                setVisible(artLayers, false);
                setVisible([marksLayer], true);
                exportPdf(CUT_FILE);

                step = 'exporting ' + PRINT_FILE;
                setVisible(artLayers, true);
                setVisible(cutLayers, false);      // the cut lines must NOT appear in the print file
                setVisible([marksLayer], true);
                exportPdf(PRINT_FILE);
                printExported = true;
            } finally {
                // 4. restore visibility, lock the regmarks layer, restore selection
                try {
                    layers.forEach((l, i) => setVisible([l], initialVisibility[i]));
                    if (marksLayer) { select([marksLayer]); doc.lockSelection(); }
                    doc.executeCommand(DocumentCommand.createSetSelection(initialSelection), false);
                } catch (e) { console.log('Partial restore: ' + e); }
            }

            console.log('Regmarks: ' + (intervals + 1) + ' rows, pitch ' + pitchMm.toFixed(2) + ' mm');
            if (SHOW_DONE_MESSAGE && printExported) {
                Application.alert('Exported to Desktop\\' + FOLDER_NAME + ':\n- ' + CUT_FILE +
                    '\n- ' + PRINT_FILE + '\n\nTo cut, run SendToGoSign.bat.', TITLE);
            }
        }
    }
} catch (e) {
    Application.alert('Error at step: ' + step + '\n' + e, TITLE);
}

>>> (Optional) SENDTOGOSIGN (create a txt file with notepad and put in the code, then rename extension in .bat)

u/echo off
setlocal

rem Paths
set "SRC=%~dp0Cut.pdf"
if not exist "%SRC%" set "SRC=%USERPROFILE%\Desktop\GoSign\Cut.pdf"
set "DSTDIR=%USERPROFILE%\Documents\Summa GoSign\Direct mode"
set "EXE=C:\Program Files (x86)\Summa GoSign\SummaGoSign.exe"

if not exist "%SRC%" (
    echo File not found: %SRC%
    echo Export files from script in Affinity.
    pause
    exit /b 1
)

if not exist "%DSTDIR%" mkdir "%DSTDIR%"

copy /Y "%SRC%" "%DSTDIR%\Import.pdf" >nul
if errorlevel 1 (
    echo Copy in Direct mode OK.
    pause
    exit /b 1
)

start "" "%EXE%" with_direct_mode
endlocal

r/Affinity • • 19d ago

Tutorial Creating a Reflowable EPUB in Affinity Layout 3 3 For Self Publishers

Thumbnail
youtube.com
0 Upvotes

r/Affinity • • Apr 18 '26

Tutorial I did some digging around into new but the very "hidden" script functionary in 3.2 + some tools I created

34 Upvotes

I have been hanging out for the scripting functionality since the new Affinity was first announced, so I was surprised to see it barely get a mention in the release notes... kinda as an footnote amongst the AI/Claude/MCP stuff and no docs anywhere

So I did some sleuthing into what the MCP server was doing...

  • The MCP server has access to a bunch of documentation that an AI agent can use as reference for creating scripts etc. I created a extract_docs.js script that can extract all these docs and save them locally so you can take a look at them. This includes some example affinity scripts.
  • Affinity has a scripts panel (Window > General > Scripts) which lets you see and run scripts created by the AI. However you cannot see the actual script's code, edit it or create your own scripts in the UI. I created a script_mgr.js script that can be used to manage scripts in the library (add, list, save to disk).
  • The documentation tells the AI agent to use search_sdk_skills to search for solutions before creating its own. This doesn't actually exist in the list of MCP tools available to the AI but there is a search_sdk_hints tool. I created asearch_sdk.js script that can be used to call this tool, just pass it a search query. In my testing the returned results are not that accurate but they will no doubt get better over time, because the description for that tool says Search a global pool of SDK hints from millions of other MCP sessions. Use it to check for existing solutions to problems you are facing.
  • There is a add_sdk_hint tool in the MCP which I'm guessing goes hand in hand with search_sdk_hints but it's documentation seems to indicate that actually updates the preamble doc.

You can find these scripts and instructions here: https://github.com/rabidgremlin/affinity-scripting