Giter Site home page Giter Site logo

bigjk / snd Goto Github PK

View Code? Open in Web Editor NEW
453.0 14.0 17.0 7.45 MB

Sales & Dungeons — Thermal Printer as D&D / TTRPG Utility

Home Page: https://sales-and-dungeons.app/

License: MIT License

Go 36.36% HTML 0.14% JavaScript 1.58% SCSS 1.74% Shell 0.55% Dockerfile 0.20% TypeScript 54.70% Python 4.73%
dnd-tools thermal-printer dnd5e dungeons-and-dragons epson osr ttrpg dungeon-master tabletop-gaming llm

snd's Introduction

S&D Header


Sales & Dungeons

Sales & Dungeons

Discord GitHub Discussions GitHub release (latest by date)

Sales & Dungeons — Thermal Printer as D&D Utility.

With Sales & Dungeons you can create highly customizable handouts, quick reference and much more for your Dungeons and Dragons (or other PnP) Sessions. Most Thermal Printer are small in size and can be taken with you and kept right at the gaming table. Use-cases range from printing out magic items, spells or a letter that the group found to little character sheets of your players to use as DM note. The possibilities are nearly endless!

Printer SetupTested PrinterWiki

Important: If you have trouble getting this to work it's best to drop by our Discord.

Screenshot

Screenshot Generator

Screenshot AI

Features

  • Works on
    • Windows
    • Mac (Intel, M1)
    • Linux (x64, ARM64)
    • Raspberry Pi (ARMv6, ARMv7)
    • Anything else go can be compiled on
  • Extensive templating system through Nunjucks
  • Extensive random generator system
  • Various connection methods
    • Windows Direct Printing
    • Raw USB Printing
    • CUPS (Linux, Mac)
    • Serial
  • Import & Export templates and data sources
  • Fast access to external data sources like Open5e (instant access to SRD monsters, spells and more)
  • Import data from other sources:
    • CSV
    • FoundryVTT Modules
    • Fight Club 5e XML Format
    • 5eTools
  • Access Community Templates, Generators & Data Sources from within the App
  • AI LLM Support (OpenAI, OpenRouter, Custom Local)
    • Generate entries by prompt using the power of AI
    • Translate entries by prompt
    • Execute AI prompts in your templates and generators
    • Support for using Local LLMs (for example via LM Studio) or any custom endpoints that are compatible with OpenAI API
  • Cloud sync for templates, generators and data sources

📁 Download

You can find the latest version on the release page:

🍎 Mac

The mac bundles are not signed at the moment so you might face the following problems when opening the application:

It's not opening because it's from a unverified developer

If your mac is telling you that this app is from a unverified developer you can allow it via the "Privacy & Security" settings. More info: Open a Mac app from an unidentified developer

It's not opening because the app "is damaged"

On M1, M2, etc. it can happen that the app is reported as damaged. Just copy Sales & Dungeons into your Applications folder and execute the following command to allow it to run:

xattr -d com.apple.quarantine "/Applications/Sales & Dungeons.app/"

🐳 Docker

The headless version of Sales & Dungeons (using LibUSB) is also available via a docker container:

  1. docker pull ghcr.io/bigjk/snd:master (container)
  2. docker run --expose 7123:7123 --device=/dev/bus/usb -v /some/place/to/persist:/app/userdata ghcr.io/bigjk/snd:master (change /some/place/to/persist to a folder where the user data should be persisted to)
  3. Open http://127.0.0.1:7123 in your favorite browser
Docker Compose Example
version: "3"
services:
  snd:
    image: ghcr.io/bigjk/snd:master
    ports:
      - "7123:7123"
    devices:
      - "/dev/bus/usb"
    volumes:
      - "/some/place/to/persist:/app/userdata"

Printer Requirements

At the moment Sales & Dungeons only supports the ESC/POS (Epson Standard Code) control codes, which is still one of the most used control code set. Check if a thermal printer you are interested in mentions ESC/POS or Epson in the description or manual.

In general the rule of thumb is:

  • Most cheap chinese thermal printer found on Amazon or AliExpress support it
  • Most epson thermal printer obviously support it
  • A lot of older Serial printer (like Metapace T-1) also support it

More specific information about tested printers can be found in the wiki: Printer-Settings

How It Works

Sales & Dungeons

Templates: Templates are created in HTML (and CSS) in combination with the Nunjucks templating language. You can imagine the templates as little websites. That makes it possible to use all the nice and convenient layout options that HTML and CSS has to offer and even include any common framework you might need (e.g. Fontawesome for Icons).

Rendered HTML: After creating a template you can create entries with the data you want and print them. Nunjucks will create the rendered HTML from the data you want to print.

Rendered Image: Then this HTML get's converted to a image. Currently this conversion is done by Chrome via the Chrome Debug Protocol. Although Chrome seems like a huge overkill for just HTML-To-Image conversion it's the standard solution at the moment because it supports most of the modern HTML and CSS features.

ESC / POS Commands: The last step before our awesome template hits the Printer is the conversion from the rendered image to the "draw image" command of the printer.

Printer: The generated command will then be sent to the printer and printed. Now your template is ready to be used!

🎉 🎉 🎉

Printers, Templating & Building

If you want to see what printers were already tested, which settings they need, how the templates work or how you can build Sales & Dungeons yourself please visit the wiki.

Thanks to all contributors ❤

Thanks to JetBrains

This Project is supported with a JetBrains License through the Open Source Support Program.

JetBrains Logo (Main) logo.

Found the project useful? 🥰

ko-fi

Credits

Icons used in the Sales & Dungeons Logo were made by Smashicons, Good Ware from www.flaticon.com

snd's People

Contributors

bigjk avatar dependabot[bot] avatar nbadal avatar nicholaiii avatar trevorklar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

snd's Issues

Standardized Data Sources

So I was writing up an issue to say that it sucks that the DnD community hasn't started to standardize their data for stuff like this, but that it would be great if you supported More Purple More Better format and the Fight Club format because they have active communities keeping their compendiums up to date and you can get various additional content.

But it looks like Fight Club is already working with people to standardize their system and as it has a huge wealth of stuff I don't think you would need to bother with MPMBs.

Here is a blog post about the Fight Club system https://donfarland.com/technology/fight-club-5-compendium-update which also links to their GitHub.

It's all xml so it should be straight forward to incorporate

Supporting star printer protocol

As far as I can see there are mainly 2 types of printer protocols used. Epson (ESC) and Star. Currently only Epson is supported because that's what most cheaply sold printer used. Maybe in the future if there was demand adding the star protocol should be considered.

feature: Data skeleton define variable types (i.e. Lists, Checkboxes, etc.)

Using snd frequently in the past weeks, I must say, this tool is "THE SH*IT" (as in awesome)!

However when I add new entries manually, I found, that it would be super useful, to have data fields, that can be set int the data skeleton. For example:
"requires_attunement": (bool)"" Would show up in "create new entry" as a checkbox (inspiration taken by the already existing global config feature)

Also lists would help a lot like rarityies, types (i.e Wondorous item, Ring, Armour, etc.)

Cheers! :)

Add optional schema definitions to data skeleton

Currently the "schema" of a templates data is derived kinda vaguely from the data skeleton. This is a relic from S&D just being a small proof-of-concept type of application at the beginning. Defining a image in the data skeleton already introduced a additional syntax inside the JSON.

{
  "icon": "!IMAGE"
}

it the future it should be possible to OPTIONALLY define what input should be shown for a field + some kind of default value for a preview while editing. A example to illustrate the idea:

{
  "name": "!TEXT=Default Name",
  "description": "!TEXTAREA=Some long default text",
  "number": "!NUMBER=0",
  "dropdown": "!DROPDOWN:A,B,C=A"
}

That way we can map custom components to the same data types and which should make entry creation and editing more pleasant.

feature: dndbeyond item importer

Not sure, how many others are using dndbeyond but here it goes:

Would be very convenient if one could import items (sure monsters would be great, but I guess make it that much more complex).
I assume there would be a need for the dndbeyond cobalt cookie to be saved in the settings.

Then one could either insert the item URL and the data could get read directly form the site.
Inspired by: https://github.com/MrPrimate/ddb-importer

Should snd move to a different templating engine?

Currently snd uses doT.js for it's templating. I choose it at first because I used it in a project ages ago and knew that it would work. After working with it a bit more I feel like it would be a good idea to consider moving to a different templating engine (before it's too late).

1. The Documentation
I think the templating library should have a good documentation so that it is easy to pick up by people. doT nearly has no documentation. The only real source of information is one advanced example file.

2. Extensibility
The main feature of snd is to build cool templates and it would be beneficial to have a templating language that could be extended with useful features. doT unfortunately isn't extensible at all.

3. Intuitive Syntax
This point is probably a bit subjective but I feel like the syntax of the more advanced features of doT feels really strange and unintuitive.

Stuff like that:

{{##def.testFunctionWithParam = function(str) {
		return "My name is: " + str;
	}
#}}

{{##def.mytestparam: {{=it.name}} #}}
{{#def.testFunctionWithParam(def.mytestparam)}}

4. Full Logic
The templating engine needs support for "complex" logic. It's not just enough to put the data straight into the template. There needs to be ways to loop over arrays in the data, manipulate the data for the template and do conditional stuff. That's actually the only point where I can't really complain about doT, as it makes every logic that javascript offers available to the template.

Possible Templating Languages

1. EJS

It's essentially just Javascript so complex logic is not a problem.

2. Nunjucks

Has the style of syntax you would find in templating of CMS-type of stuff. It's really extensible. Good documentation and a lot of functions out of the box.

3. Squirrelly

It's actually really similar to Nunjucks but a bit more lightweight (less functions out of the box) and faster. I don't think speed is really a problem as the templates we deal with are still minimal in comparison to the CMS stuff these templating engines normally have to deal with.


My personal favorite so far is Nunjucks as it feels mature, well documented, there are a lot of functions already present and It's really easy to extend. I also like the syntax.


If anyone has any input on this I would be happy to hear it! 😃

Experimenting with different image printing commands

Currently the Epson command [GS v 0] is used to print the template on the printer. In theory this command is a "obsolete command" but it seems like most printer still have it for backward compatibility.

It is recommended to use graphics function (GS ( L <Function 50> and GS ( L / GS 8 L <Function 112> )

So it might be a good idea to check out the other image printing commands in the future.

Sometimes Characters instead of Image is printed

This behaviour is sometimes encountered on mac while using cups. Printing characters instead of a image might indicate that the printer didn't correctly receive the raster image command and is trying to print the image bytes as characters. It needs to be investigated when this happens and if it's a problem with cups, the printer or S&D itself.

Trouble printing images loaded from URL

Hi guys!

Not sure if anyone can reproduce this, but somehow I'm running into trouble when adding images from a URL to the Print skeleton.
I use a global config (Checkbox) no show/hide the image. In the preview the image is shown just fine. However the print itself shows no image. Other image elements (Icons and frame) are printing fine. Also using the "Save Image" button does not show the added image.

Expected Output

Output I got:

But when I edit the Template and load the data Skeleton of the same item, it prints fine as long as I load the data skeleton of the same item. If I use the default (last used entry) in the edit mode, it gives me the error:

Error: html to image rendering failed: png: invalid format: invalid image size: 0x0

Re-loading the item in the "Data Skeleton" page solves that problem and it prints the image just fine.

I added some image filtering options so that the output is kind of usable (values can be changed via global config). Maybe someone else needs this, so I'm posting my print template here.

Print Template

Print Template
<style>
    @font-face {
        font-family: "nodesto-condensed";
        src: url("/proxy/https://github.com/jonathonf/solbera-dnd-fonts/raw/master/Nodesto%20Caps%20Condensed/Nodesto%20Caps%20Condensed.otf") format("opentype");
        font-weight: normal;
    }
    @font-face {
        font-family: "Scaly Sans";
        src: url("/proxy/https://github.com/jonathonf/solbera-dnd-fonts/raw/master/Scaly%20Sans/Scaly%20Sans.otf") format("opentype");
        font-weight: normal;
    }
    .CardFront {
        width: auto;
        border-radius: 8px;
    }
    .CardContent {
        padding: 10px 10px 16px;
        font-family: "Scaly Sans", serif;
        font-style: normal;
        font-weight: 300;
    }
    .CardContent hr {
        margin: 0;
        height: 3px;
    }
    .Title {
        padding: 2px 8px;
        background-color: #e8ebec;
        border-top-left-radius: 8px;
        border-top-right-radius: 8px;
        font-size: 2rem;
        line-height: 2rem;
        font-family: "nodesto-condensed", serif;
        font-weight: normal;
        font-style: normal;
        text-transform: uppercase;
        text-align: center;
    }
    .Subtitle {
        padding: 4px;
        text-align: center;
        color: #e8ebec;
        font-size: 1.5rem;
        line-height: 1.5rem;
    }
    .DetailsContainer {
        overflow: auto;
        border-bottom-left-radius: 8px;
        border-bottom-right-radius: 8px;
    }
    .DetailsContainer :first-child {
        padding-top: 8px;
    }
    .DetailsContainer :last-child {
        padding-bottom: 8px;
    }
    .DetailsBlock {
        padding: 3px 8px;
        background-color: #e8ebec;
        font-size: 1.7rem;
        line-height: 1.7rem;
    }
    .CardFooter {
        margin-top: 4px;
        display: flex;
        justify-content: space-between;
        color: #e8ebec;
        font-size: 1.5rem;
        line-height: 1.25rem;
        font-weight: bold;
    }
    .Category {
        font-size: 2.9rem;
        line-height: 2.9rem;
        font-family: "nodesto-condensed", serif;
        font-weight: normal;
        font-style: normal;
        text-align: center;
    }
    .Cost {
        font-size: 1.9rem;
        line-height: 2.9rem;
        font-family: "nodesto-condensed", serif;
        font-weight: normal;
        font-style: normal;
        text-align: center;
    }
    .center {
        display: block;
        margin-left: auto;
        margin-right: auto;
        width: 90%;
    }
    .Avatar {
        font-size: 1.9rem;
        line-height: 2.9rem;
        font-family: "nodesto-condensed", serif;
        font-weight: normal;
        font-style: normal;
        text-align: center;
    }
    .FileterdImage {
        -webkit-filter: grayscale(200%) contrast(200%) brightness({{config.brightness}}%);
        filter: grayscale(200%) contrast(200%) brightness({{config.brightness}}%);
    }
    img {
        -webkit-filter: grayscale(200%) contrast(200%) brightness({{config.brightness}}%);
        filter: grayscale(200%) contrast(200%) brightness({{config.brightness}}%);
    }
</style>
{% set color = "black" %}
<div class="CardFront" style="background-color: {{ color }}">
    <div class="CardContent">
        <div class="Title">
            <img src="{{ images[(it.dndbeyond.filterType+".png")] }}" alt="" width="30"> {{ it.name }}
        </div>
        <div class="Subtitle">{{ it.dndbeyond.type+" - " if it.dndbeyond.type}} {{ it.Item.system.rarity | capitalize }} {{ "("+it.requires_attunement+")" if it.requires_attunement }}</div>
        <div class="DetailsContainer">
            <div class="DetailsBlock">
                {{ it.desc | replace(r/\*\*([^\*]*)\*\*/g, '<strong>$1</strong>') | replace(r/_([^_]*)_/g, '<em>$1</em>') | replace(r/\n[\*-] /g, '\n• ') | replace("@Compendium[dnd5e.rules.w7eitkpD7QQTB6j0]","") | safe }} {% if
                config.showImage %}
                <img src="{{it.dndbeyond.avatarUrl}}" alt="" class="center" />
                {% endif %}
            </div>
        </div>
        <div class="CardFooter">
            <div class="Category">{{ it.type }}</div>
            <div class="Cost">
                {% if it.weight %}
                <img src="{{ images[('scale.png')] }}" alt="" width="30" />
                {{ (" "+it.weight+"lbs" if it.weight)+(" " if it.price)}} {% endif %} {% if config.value_overwrite > 0 %} {{ "Value: "+config.value_overwrite+"Gp" if config.value_overwrite}} {% else %} {{ "Value: "+it.price+"Gp" if
                it.price}} {% endif %}
            </div>
        </div>
    </div>
</div>

Better scripting

Currently scripting is very basic and frail. Next steps should be:

  • Graceful aborting
  • Syntax checking without running the script
  • Piping script logs to frontend
  • More functions to interact with templates and entries

QR Code generation

Just in case someone can use this:

Wanted to create a QR code that opens the URL to the dndbeyond entry of a spell. Got it working with the following:

<img style="display: block; margin-left: auto; padding: 20px;  margin-right: auto; width: 50%;" 
src="{{"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data="+"https://www.dndbeyond.com/spells/"+config.name | replace(" ","-") | lower+""}}"></img>

So if the config has the Spells name, it should create the correct QR code.
Screenshot 2024-05-20 160019

ARM versioned builds for RPi

We only have a linux-arm build atm but we should probably have separate ones for multiple arm versions to make it easier to use on RPi's. I don't even know what version this defaults to if no arm version is specified.

If GOOS=arm there is a GOARM env variable that we can set to:

  • GOARM=5
  • GOARM=6
  • GOARM=7

@nbadal I guess this isn't hard to add to the build action? 🤔

Open Dashboard in Browser

An Option would be great to "host" the snd Dashboard on a server.
So that i could install snd on an raspberry pi + connected printer and connect to it with an standard Windows Browser.

But all in all awesome project :)

Make printing width configurable

Currently the template is statically 384px width because that's what most 58mm printer use as printing area but it should be changeable in the settings page of the frontend to different value.

Bundling MacOS builds into .app folders

For MacOS we should switch to distributing a complete .app folder in the future, so that S&D is a Application that can be dropped into the application folder with it's own Icon.

Target folder structure would probably be:

Sales & Dungeons.app/
└── Contents
    ├── Info.plist
    ├── MacOS
    │   └── snd
    │   └── frontend/...
    │   └── data/...
    │   └── version.txt
    └── Resources
        └── icon.icns

Additionally we should change the default userdata folder on MacOS so that data will be kept outside of the app bundle. Something like ~/Documents/Sales & Dungeons/. That way the app can easily be updated by just overwriting.

Info:

Documentation

There is still a lot of documentation missing at the moment.

Documentation needed for:

  • Building
  • Printing Types
  • Templating
  • Scripting

I would really like to keep the README.md from being bloated too much. Do you guys think the Github Wiki is a good enough place for the documentation or is there any need for a more dedicated / external documentation solution?

Infinite loops in Javascript that is contained in Templates

Opening this issue to keep track of possible solutions. Currently there is a problem that if a template contains javascript that blocks infinitely the whole application will freeze and needs a restart. Examples would be:

<script>
while(true) {}
// or
for (let i = 0; true; i++) { }
// or
for (let i = 0; i < 100; i) { }
// and so on...
</script>

Rendered templates will be previewed in iframes and because this iframe is from the same origin it will be run in the same thread as the rest of the applications. That results in the problem when the iframe content blocks the whole application blocks.

Solution 1

Force iframe to be on separate thread. This doesn't seem to work at the moment, as I need the iframe to have the allow-same-origin option which seems to prevent iframes from running in their own thread even if the sandbox option is used.

Solution 2

I tried to switch to the webview tag. This also doesn't seem to be working. In theory the webview sounds perfect, but there is a issue that makes it apparently impossible to directly load arbitrary HTML into it and have the contained scripts run. The HTML will show fine but no scripts are working.

Unify cmd packages?

Currently there is

  • /cmd/headless
    • Simple headless version without any native dependencies. It's just go and can be cross-compiled to any target OS from any other OS.
  • /cmd/headless-libusb
    • Headless version with native dependency (libusb) for direct printing over USB.
  • /cmd/windows-direct
    • Electron window + Windows syscalls for direct printing on Windows.

After adding libusb I think it's a good time to rethink this approach. Maybe you are using MacOSX and still want to have a electron window and libusb. Currently that is not covered by these 3 packages.

In Go it's possible to activate and deactivate features based on OS or tags that can be specified while building. I think this would be a better solution than separate packages and would allow users to mix and match what they need.

My Idea

  • Remove /cmd/headless /cmd/headless-libusb and /cmd/windows-direct
  • The main.go will be moved to /cmd/main.go
  • Without specifying any tags main.go will be the normal headless version without any native dependencies
  • On windows the windows direct printing will be automatically enabled because it only requires syscalls and no native dependencies that need to be compiled. So there is no downside to just activating it when OS == windows

Optional Tags

  • LIBUSB will enable usb printing and require libusb-1.0 to be installed
  • ELECTRON will enable a electron window where the frontend is shown

Example

headless without libusb or electron window

cd /somewhere/.../snd/cmd
go build

libusb

cd /somewhere/.../snd/cmd
go build -tags="LIBUSB"

libusb + electron

cd /somewhere/.../snd/cmd
go build -tags="LIBUSB ELECTRON"

This also would help to keep it more DRY because the 3 packages currently all contain the same main() function with just minor changes.

I pushed it to a seperate branch so feel free to take a look at it cmd-unify/cmd. If there are no objections I will merge it into master.


Just a little info for anybody that is not familiar with go. The init() function of a file will be executed before the main function. This can be combined with the build tags / constraints to enable or remove stuff depending on the tags or OS.

init(): https://golang.org/doc/effective_go.html#init
build constraints: https://golang.org/pkg/go/build/

[Request] Add support for LM Studio's local API server

LM Studio allows to easily run any HuggingFace gguf LLM locally (LLama, Mistral, etc) and open an API endpoint.

image

Lightweight models offer satisfying results and can easily be ran with 16GB RAM and 8GB VRAM. Would that be possible to add support for a self-hosted API server in the AI section?

False Positive Trojan Warning on Windows

Hello, on startup windows defender is blocking your application with the following message:

image

Can you pls take a look into this issue or can you tell me what the leakless.exe file is?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.