Skip to content
This repository was archived by the owner on Aug 31, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Always check text files out with LF
* text eol=lf
79 changes: 52 additions & 27 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,65 @@ name: CI

on:
push:
branches:
- main
branches: ["**"] # run for every branch
pull_request:
branches:
- main
branches: ["**"]
workflow_call:

jobs:

test:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04

# Same Mesa-headless settings as in the Dockerfile
env:
GOPATH: /home/runner/go
LIBGL_DRIVERS_PATH: /usr/lib/x86_64-linux-gnu/dri
GALLIUM_DRIVER: llvmpipe
LIBGL_ALWAYS_SOFTWARE: "true"
EGL_PLATFORM: surfaceless
MESA_GL_VERSION_OVERRIDE: "4.6"

steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: stable

- run: go get -u golang.org/x/lint/golint
- run: sudo apt install libegl1-mesa-dev libgl1-mesa-dev libglfw3-dev
- run: sudo apt install libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev
- run: sudo apt install libusb-1.0-0-dev libfreenect-dev
- run: go mod download

- name: Check go mod
run: |
go mod tidy
git diff --exit-code go.mod
git diff --exit-code go.sum

- run: gofmt -s -d .
- run: $GOPATH/bin/golint -min_confidence 0.3 $(go list ./...)
- run: go build -tags kinect ./cmd/shady/
- run: go test -test.v -race -cover ./...
# ✨ Source code & Go toolchain
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: stable

# ✨ System packages
- name: Install build-time & runtime deps
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
git curl ca-certificates build-essential python3 pkg-config \
ffmpeg \
libegl1 libegl1-mesa-dev libgl1-mesa-dev libglx-mesa0 \
libgl1-mesa-dri mesa-utils \
libglfw3-dev \
libx11-dev libxcursor-dev libxi-dev \
libxinerama-dev libxrandr-dev libxxf86vm-dev \
libusb-1.0-0-dev libfreenect-dev # still needed for “kinect” tag

# ✨ Go dependencies & static checks
- name: Download Go modules
run: go mod download

- name: Ensure go.mod / go.sum are tidy
run: |
go mod tidy
git diff --exit-code go.mod
git diff --exit-code go.sum

- name: Lint & format
run: |
go install golang.org/x/lint/golint@latest
gofmt -s -d .
"$GOPATH/bin/golint" -min_confidence 0.3 $(go list ./...)

# ✨ Build & test
- name: Build
run: go build -tags kinect ./cmd/shady/

- name: Test
run: go test -v -race -cover ./...
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/shady.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# docker build -t shadertoy-render .
# docker run --rm -v "$(pwd)":/work -e RES=2560x1440 -e FPS=60 shadertoy-render shader.glsl audio.mp3 out.mp4
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

# 1️⃣ Core build/runtime deps
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates build-essential python3 pkg-config \
ffmpeg \
libegl1-mesa libegl1-mesa-dev libgl1-mesa-dev libgl1-mesa-dri mesa-utils \
libglfw3-dev \
libx11-dev libxcursor-dev libxi-dev \
libxinerama-dev libxrandr-dev libxxf86vm-dev \
&& rm -rf /var/lib/apt/lists/*

# 2️⃣ Go toolchain (latest stable)
ARG GO_VERSION=1.24.4
RUN curl -fsSL https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz | tar -C /usr/local -xz
ENV GOPATH=/go
ENV PATH=/usr/local/go/bin:${GOPATH}/bin:$PATH

# 3️⃣ Build **shady** once inside the image
RUN go install github.com/polyfloyd/shady/cmd/shady@latest

# 4️⃣ Head-less EGL / Mesa software driver
ENV LIBGL_DRIVERS_PATH=/usr/lib/x86_64-linux-gnu/dri \
GALLIUM_DRIVER=llvmpipe \
LIBGL_ALWAYS_SOFTWARE=true \
EGL_PLATFORM=surfaceless \
MESA_GL_VERSION_OVERRIDE=4.6
# 5️⃣ Helper script (same dir as Dockerfile)
COPY render_shader.sh /usr/local/bin/render_shader
RUN chmod +x /usr/local/bin/render_shader

WORKDIR /work
ENTRYPOINT ["render_shader"]
50 changes: 50 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
############################################
# shadertoy-render: run unit-tests at build
############################################
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

# 1️⃣ Core build & runtime packages (Mesa head-less + dev libs)
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates build-essential python3 pkg-config \
ffmpeg \
libegl1-mesa libegl1-mesa-dev libgl1-mesa-dev libgl1-mesa-dri mesa-utils \
libglfw3-dev \
libx11-dev libxcursor-dev libxi-dev \
libxinerama-dev libxrandr-dev libxxf86vm-dev \
libusb-1.0-0-dev libfreenect-dev \
&& rm -rf /var/lib/apt/lists/*

# 2️⃣ Go toolchain (latest stable at build time, or pin via --build-arg)
ARG GO_VERSION=1.24.4
RUN curl -fsSL https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz | tar -C /usr/local -xz
ENV GOPATH=/go
ENV PATH=/usr/local/go/bin:${GOPATH}/bin:$PATH

# 3️⃣ Copy source and resolve modules up-front (cache-friendly)
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# 4️⃣ Mesa software rasteriser – same flags as CI
ENV LIBGL_DRIVERS_PATH=/usr/lib/x86_64-linux-gnu/dri \
GALLIUM_DRIVER=llvmpipe \
LIBGL_ALWAYS_SOFTWARE=true \
EGL_PLATFORM=surfaceless \
MESA_GL_VERSION_OVERRIDE=4.6

# 5️⃣ 🧪 Run the test-suite; build aborts if anything fails
RUN go test -v -race -cover -tags kinect ./...

# 6️⃣ Build & install the CLI executable
RUN go install -tags kinect ./cmd/shady

# 7️⃣ Helper wrapper (kept from your original image)
COPY render_shader.sh /usr/local/bin/render_shader
RUN chmod +x /usr/local/bin/render_shader

# 8️⃣ Final runtime setup
WORKDIR /work
ENTRYPOINT ["render_shader"]
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ development and hacking.


## Usage
### Docker (simplified executable)
Runs in serverless docker based mode:
```bash
# docker build -t shadertoy-render .
# docker run --rm -v "$(pwd)":/work -e RES=2560x1440 -e FPS=60 shadertoy-render shader.glsl audio.mp3 out.mp4
```
will put out.mp4 into a folder from where you started it and will take in from that folder shader.glsl audio.mp3 files. It is slowish (on M4 Max 1.8 fps for the command above and [this](https://www.shadertoy.com/view/W3VGWW) shader)
Feel free to change `render_shader.sh` for more complicated input configurations.

### Installation
```sh
go install github.com/polyfloyd/shady/cmd/shady@latest
Expand Down
52 changes: 52 additions & 0 deletions render_shader.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -euo pipefail

# Tunables
FPS=${FPS:-30} # env-override: FPS=60 ./render ...
RES=${RES:-3840x2160} # env-override: RES=1920x1080 ...
A_CODEC=${A_CODEC:-aac} # “copy” to keep source codec, aac default
A_BITRATE=${A_BITRATE:-192k}
V_CODEC=${V_CODEC:-libx264rgb}
V_PRESET=${V_PRESET:-slow}
V_LOSSLESS=${V_LOSSLESS:--crf 0} # empty → normal CRF 18 encode
PIX_FMT=${PIX_FMT:-rgb24}

OUT=${3:-output_4k.mp4} # 3rd arg or fallback

[[ $# -lt 2 ]] && {
echo "Usage: $0 shader.frag audio.(mp3|wav|flac) [output.mp4]" >&2
exit 1
}

SHADER=$1
AUDIO=$2

# Length → Frame count
DUR=$(ffprobe -v error -select_streams a:0 \
-show_entries stream=duration \
-of default=noprint_wrappers=1:nokey=1 "$AUDIO")

FRAMES=$(python3 - <<'PY' "$DUR" "$FPS"
import math, sys
dur, fps = map(float, sys.argv[1:])
print(math.ceil(dur * fps))
PY
)

[[ -z $FRAMES || $FRAMES -le 0 ]] && {
echo "❌ Could not compute frame count (DUR=$DUR, FPS=$FPS)" >&2
exit 1
}

# Render frames → pipe raw RGB → ffmpeg (encode + mux audio)
shady -i "$SHADER" -g "$RES" -f "$FPS" -n "$FRAMES" \
-ofmt rgb24 -map iChannel0=audio:"$AUDIO" | \
ffmpeg -stats -y \
-f rawvideo -pixel_format rgb24 -video_size "$RES" -framerate "$FPS" -i - \
-i "$AUDIO" \
-map 0:v:0 -map 1:a:0 -shortest \
-c:v "$V_CODEC" $V_LOSSLESS -preset "$V_PRESET" -pix_fmt "$PIX_FMT" \
-c:a "$A_CODEC" -b:a "$A_BITRATE" \
-movflags +faststart "$OUT"

echo "✅ Done ➜ $OUT"
2 changes: 1 addition & 1 deletion renderer/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (err CompileError) PrettyPrint(out io.Writer) {
}

func (err CompileError) markers() []errorMarker {
errLineRe := regexp.MustCompile(`(?m)^(\d+):(\d+)\((\d+)\): (.+)$`)
errLineRe := regexp.MustCompile(`(?m)^(\d+):(\d+)(?:\((\d+)\))?: (.+)$`)

var markers []errorMarker
matches := errLineRe.FindAllStringSubmatch(err.log, -1)
Expand Down
Loading