LUSON MEDIA

LUSON MEDIA

At Luson Media, I brought my energy and expertise to the creation and maintenance of hundreds of Financial Service Professional websites. I worked with a team of other designers from different fields to craft comprehensive branding systems, and websites that would work seamlessly with pre-existing design frameworks. In addition, I created digital ads and other advertising materials for a range of clients to help them show up the best that they can online. I brought my enthusiasm every day (why yes, that is me participating in an annual hot dog eating contest), and prided myself on getting even heavy work loads done well, and done fast.

Regarding my website design work, I worked primarily with the oceanwp theme, and the elementor and elementor pro plugins within a multisite environment to build websites. Within those two systems, further customization with .css and javascript were regular and varied. I pride myself on an ability to make the impossible possible with uniquely coded solutions, and always enjoy a puzzle. Me and the rest of the web team worked within an AWS multisite environment, though some FSPs had unique websites that required special exceptions.

Website Work

At Luson Media, we provide custom websites for Financial Service Professionals. These projects can range from clients needing a fast, templated build ready to go in a week, to more personalized projects with specific marketing intentions in mind. The two projects below demonstrate a more templated build (5280rg), and a more specialized approach (Educational Association).

5280rg

For 5280rg, I prided myself on developing unique features that turned a website template into a branded and personalized experience. I developed a unique contact form system that would return resources to clients upon form submissions that integrated into their CRM system, which helped streamline their marketing flow and made it easier to gather relevant contact information for interested potential clients. 

Educational Association

For the Educational Association, I had to create a completely custom website that highlighted the six-step plan he had developed for his clients’ retirement journey. It’s always fun to work with such a colorful brand, and I tried my best to use these colors in meaningful ways: corresponding to different steps in the retirement journey, and through eye-catching, interactive elements across the site.

Meraki | New and Old

After being provided a style guide, written material, and images for the new Meraki site I had to craft a new vision that would align with shifting values, while incorporating a more modern design. This was a fun, collaborative process that incorporated a custom-coded service wheel with description pop-ups, content-centered design with shifting, fluid elements to encapsulate the reactive nature of the company. 

Before

Genesis | New and Old

Like the Meraki project, I worked with a Graphic Designer within Luson to create a new branding guide for the Genesis company. Using this, I updated their outdated website into one that functioned better, while highlighting their full range of services and elevating the user experience with more comprehensive user flow. Per the client specifications, I was able to create a custom stock ticker that would scroll on the bottom of their site without the need to pay for any third-party extensions. See below for an example of the code used to create the custom “ticker” at the bottom of their website!

Before
📄
Ticker.js
<script>
window.addEventListener('load', function () {

  const ticker = document.querySelector('.ticker');

  if (!ticker) return;

  const apiKey = 'S10HAO5L3JIBNTXX';

  const symbols = [
    { name: 'S&P 500', symbol: 'SPY' },
    { name: 'NASDAQ', symbol: 'QQQ' },
    { name: 'DOW', symbol: 'DIA' }
  ];

  ticker.innerHTML = '<div class="ticker-item">Loading market data…</div>';

  const requests = symbols.map(function (item) {

    const url =
      'https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=' +
      item.symbol +
      '&apikey=' + apiKey;

    return fetch(url)
      .then(function (res) {
        return res.json();
      })
      .then(function (data) {

        console.log(item.symbol, data);

        const quote = data['Global Quote'];

        /* HANDLE FAILED API RESPONSES */
        if (
          !quote ||
          !quote['05. price'] ||
          !quote['10. change percent']
        ) {

          console.warn('Missing quote data for:', item.symbol);

          return {
            name: item.name,
            price: '--',
            change: 'N/A',
            dir: 'down'
          };
        }

        const price = parseFloat(quote['05. price']);
        const changeText = quote['10. change percent'];
        const changeNumber = parseFloat(changeText);

        return {
          name: item.name,
          price: price.toFixed(2),
          change: changeText,
          dir: changeNumber >= 0 ? 'up' : 'down'
        };

      })
      .catch(function (err) {

        console.error('Fetch failed:', item.symbol, err);

        return {
          name: item.name,
          price: '--',
          change: 'N/A',
          dir: 'down'
        };
      });

  });

  Promise.all(requests).then(function (results) {

    ticker.innerHTML = '';

    results.forEach(function (item) {

      const el = document.createElement('div');

      el.className = 'ticker-item ' + item.dir;

      el.innerHTML =
        '<strong>' + item.name + '</strong>' +
        '<span class="price">$' + item.price + '</span>' +
        '<span class="change">' + item.change + '</span>';

      ticker.appendChild(el);

    });

  });

});
</script>
🎨
Ticker.css
/*ticker tape*/
/* Outer container */
.ticker-wrap {
  width: 100%;
  overflow: hidden;
  background: #f7f9fc;
  border-radius: 8px;
  padding: 8px 0;
  box-sizing: border-box;
}

/* 3-column layout */
.ticker {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: center;
  width: 100%;
  gap: 4px;
  box-sizing: border-box;
}

/* EACH ITEM */
.ticker-item {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: 10px 6px;
  font-size: 13px;
  font-weight: 500;
  min-width: 0;
  overflow: hidden;
  text-align: center;
}

/* Prevent wrapping */
.ticker-item strong,
.ticker-item .price,
.ticker-item .change {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* LABEL */
.ticker-item strong {
  color: #161819;
  font-weight: 600;
}

/* PRICE */
.ticker-item .price {
  color: #627793;
}

/* POSITIVE */
.ticker-item.up .change {
  color: #17B022;
}

/* NEGATIVE */
.ticker-item.down .change {
  color: #B01717;
}

/* MOBILE */
@media (max-width: 768px) {

  /* KEEP 3 COLUMNS ON MOBILE */
  .ticker {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .ticker-item {
    font-size: 11px;
    gap: 4px;
    padding: 8px 4px;
  }
}

Custom Rotating Gallery Wheel

📄
Rotating-Gallery.js
<script>
document.addEventListener("DOMContentLoaded", function () {

  const wrapper = document.querySelector(".orbit-wrapper");
  const orbit = wrapper.querySelector(".e-con-inner");
  const circles = document.querySelectorAll(".orbit-circle");

  const total = circles.length;
  const angleStep = 360 / total;

  let rotation = 0;
  let isDragging = false;
  let startX = 0;
  let autoplay;

  function applyRotation() {

    orbit.style.transform = `translate(-50%, -50%) rotate(${rotation}deg)`;

    // keep content upright
    circles.forEach(circle => {
      const contents = circle.querySelectorAll(".orbit-content");
      contents.forEach(c => {
        c.style.transform = `rotate(${-rotation}deg)`;
      });
    });
  }

  function rotateNext() {
    rotation -= angleStep;
    applyRotation();
  }

  function startAutoplay() {
    autoplay = setInterval(rotateNext, 3500);
  }

  function stopAutoplay() {
    clearInterval(autoplay);
  }

  /* -----------------------
     Drag Controls
  ----------------------- */

  wrapper.addEventListener("mousedown", (e) => {
    isDragging = true;
    startX = e.clientX;
    stopAutoplay();
  });

  window.addEventListener("mouseup", () => {
    if (!isDragging) return;

    isDragging = false;

    // snap to nearest item
    rotation = Math.round(rotation / angleStep) * angleStep;
    applyRotation();

    startAutoplay();
  });

  window.addEventListener("mousemove", (e) => {
    if (!isDragging) return;

    const delta = e.clientX - startX;
    const sensitivity = 0.4;

    rotation += delta * sensitivity;
    startX = e.clientX;

    applyRotation();
  });

  /* -----------------------
     Touch support
  ----------------------- */

  wrapper.addEventListener("touchstart", (e) => {
    isDragging = true;
    startX = e.touches[0].clientX;
    stopAutoplay();
  });

  window.addEventListener("touchend", () => {
    if (!isDragging) return;

    isDragging = false;

    rotation = Math.round(rotation / angleStep) * angleStep;
    applyRotation();

    startAutoplay();
  });

  window.addEventListener("touchmove", (e) => {
    if (!isDragging) return;

    const delta = e.touches[0].clientX - startX;
    const sensitivity = 0.4;

    rotation += delta * sensitivity;
    startX = e.touches[0].clientX;

    applyRotation();
  });

  /* -----------------------
     Init
  ----------------------- */

  applyRotation();
  startAutoplay();

});
</script>
🎨
Rotating-Gallery.css
/*rotating service gallery*/

.orbit-wrapper {
  position: relative;
  width: 900px;
  height: 900px; /* diameter of the large invisible orbit */
  margin: 0 auto;
  overflow: visible;
}

.orbit-circle {
  position: absolute;
  width: 350px;
  height: 350px;
  border-radius: 50%;
  top: 50%;
  left: 50%;
	padding: 25px;
  margin: -175px; /* center itself */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transition: transform 0.5s ease, z-index 0.5s ease;
  z-index: 1;
}

/* Position each circle along the full 360° perimeter */
.orbit-circle:nth-child(1) { transform: rotate(0deg) translateY(-450px); }
.orbit-circle:nth-child(2) { transform: rotate(60deg) translateY(-450px); }
.orbit-circle:nth-child(3) { transform: rotate(120deg) translateY(-450px); }
.orbit-circle:nth-child(4) { transform: rotate(180deg) translateY(-450px); }
.orbit-circle:nth-child(5) { transform: rotate(240deg) translateY(-450px); }
.orbit-circle:nth-child(6) { transform: rotate(300deg) translateY(-450px); }

Digital Ads

Stay tuned for more work examples!

Enquire now

Give us a call or fill in the form below and we will contact you. We endeavor to answer all inquiries within 24 hours on business days.