Jump to content
Team Meuter

Team Meuter - Die Profilschärfer

Recommended Posts

We recently finished a relaunch of our agency website: https://www.meuter.de/





  • Minimalistic and modern design
  • Page transitions and preloading for a really fast browsing expierence
  • Custom content builder for blog posts, references and subpages
  • Content is king: Many case studies and blog posts


Under the hood:

  • Webpack with ES6 and SCSS
  • LQIP with Base64 Images
  • Lazy loading with lazysizes
  • Automatic generation of scrset images, Base64 placeholder images and background positions
  • Page transitions with barba.js
  • Preload pages when user hover over link
  • Interactive components which reacts on scroll events. Built with ScrollMagic
  • Handwritten template


Modules used:

  • ProFields
  • Markup Sitemap XML
  • Video embed for YouTube/Vimeo


Our Content Builder for a reference:



Clean page structure:


The code for the image generator:

// ------------------------------
// Image modifications
// ------------------------------

 * Responsive Image Options
class imageModifier {

    // Responsive Sizes from lowest to highest
    private $responsiveSizes = array(320,640,768,1024,1366,1600,1920,2560);
    private $base64ImageWidth = 20;
    private $imageOptions = array(
        'upscaling' => true

    // Return a string with the srcset information
    public function getSrcSet($image){
        // Create an emptry output string
        $srcSetOutputString = '';

        // Create each image for each size
        foreach ($this->responsiveSizes as $responsiveSizeId => $responsiveSizeWidth) {
            // Check if the image is bigger then the final size
            if($image->width >= $responsiveSizeWidth){
                // Create the image and put the url into the output string
                $srcSetOutputString .= $image->width($responsiveSizeWidth, $this->imageOptions)->url;
                // Put the width in the output string
                $srcSetOutputString .= ' ' . $responsiveSizeWidth . 'w' . ',';

        //When the original image is smaller then the highest quality
        if($image->width < $this->responsiveSizes[count($this->responsiveSizes) - 1]){
            // Create the image and put the url into the output string
            $srcSetOutputString .= $image->width($image->width)->url;
            // Put the width in the output string
            $srcSetOutputString .= ' ' . $image->width . 'w' . ',';

        // Remove last commata
        $srcSetOutputString = rtrim($srcSetOutputString, ',');
        // Return the srcSet information
        return $srcSetOutputString;

    //Returns the lowest quality image
    public function getLowestQuality($image){
        return $image->width($this->responsiveSizes[0]);

    //Returns the highest quality image
    public function getHighestQuality($image){
        // if image is bigger or same than max quality
        if($image->width >= $this->responsiveSizes[count($this->responsiveSizes) - 1]){
            return $image->width($this->responsiveSizes[count($this->responsiveSizes) - 1]);
        // When image is smaller then the highest quality
        else {
            return $image;

    // Returns the base64 data string
    public function getBase64($image){
        // Get the image path
        $imagePath = $image->width($this->base64ImageWidth)->filename;
        // Get the image extension
        $imageType = pathinfo($imagePath, PATHINFO_EXTENSION);
        // Get the data of the image
        $imageData = file_get_contents($imagePath);
        // Create the base64 Code
        $base64Code = 'data:image/' . $imageType . ';base64,' . base64_encode($imageData);
        // Return the code
        return $base64Code;

    // Returns the position point
    public function getPosition($image){
        // Get distance from top
        $distanceTop = '' . intval($image->focus()['top']);
        // Get distance from left
        $distanceLeft = '' . intval($image->focus()['left']);
        // Return the position with percent
        return $distanceLeft . '% ' . $distanceTop . '%';




Thanks for the community and Processwire. It is a joy to use 🙂

  • Like 19

Share this post

Link to post
Share on other sites

Sehr schön!

Could you tell us a bit more about the page transitions and preloading? It looks really smooth.

  • Like 2

Share this post

Link to post
Share on other sites

We used http://barbajs.org/ for the transitions. This was for me the best tool to create good transitions. It also includes a preloading/prefetch option: http://barbajs.org/prefetch.html. When the user hovers over a link, it preloads the page. The time difference between hover and click is about 250ms to 750ms in our tests. This is in the most cases enough to load the full .html document. Here is an interesting website to test it yourself: http://instantclick.io/click-test 

This is how a transition works:

  1. The user hovers over a link
  2. The browser prefetches the site (Including Base64 placeholder images)
  3. The user clicks the link (The time difference between hover and click is long enough to load the document)
  4. The actual page transition out
  5. The loading screen transition in (In most cases it will skip this step because the page is already loaded)
  6. The new page transition in

We can change the direction of the transition with data-attributes:

<a href="/arbeit/" class="button-enter introduction-button" data-transition-direction="left">Arbeit</a>



When you have other questions please feel free to ask 🙂

  • Like 11

Share this post

Link to post
Share on other sites

How would you handle Analytics? I see you are using Tag Manager, but I'm curious how the triggering of a page works. Thanks in advance!

Share this post

Link to post
Share on other sites

I include the Tag Manager script normally. You can create a trigger in the Tag Manager which react on every change in the url. The trigger is included in the Tag which creates a Google Analytics Pageview. This works perfect and is easy to configure. Here is a screenshot from the Tag Manager (The UI is on german):


  • Like 1

Share this post

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...