Artemis now offers Participate Energy Prepaid Lease.
Learn more →

Design Editor 3.0

Product Updates
January 28th, 2026
Text Link

Design Level Settings

Design Level Settings give you more control without getting in your way. Set rules for panel placement, inverter selection, and fire setbacks right at the project level, and add variable system losses to better reflect real-world conditions. Defaults handle most designs automatically, so you can move fast out of the gate. When a project needs extra precision, overrides are there when you need them. This keeps designs flexible without sacrificing consistency. The result is faster designs that still meet technical, financial, and compliance standards.

Text Link

Software Settings

Software Settings help your team start every project on the right foot. Configure global preferences like roof snapping, auto-design, and other workflow options once, and let them carry across all projects. This keeps designers aligned and cuts down on repetitive setup. Updates apply instantly, so changes take effect right away. Less time configuring, more time designing. Best practices become the default, making it easier to scale speed and accuracy together.

Text Link
// Initialize Lenis const lenis = new Lenis({ lerp: 0.1, }); // Listen for the scroll event and log the event data lenis.on(‘scroll’, (e) => { console.log(e); }); // Use requestAnimationFrame to continuously update the scroll function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); gsap.registerPlugin(ScrollTrigger); const splitTypes = document.querySelectorAll(‘.scroll-highlight’); splitTypes.forEach((char, i) => { const text = new SplitType(char, { types: [‘chars’, ‘words’] }); gsap.from(text.chars, { scrollTrigger: { trigger: char, start: ‘top 50%’, end: ‘top 10%’, scrub: 1, }, opacity: 0.2, stagger: 0.1, }); }); new WordPlay({ className: “h-2”, // the text element mode: “letter”, // choose between letter or word offset: 20, // offset if revealed by scroll speed: 0.7, delay: 0.015, // stagger delay }); .skip-link { position: absolute; top: -100px; left: 0; background: #000; color: white; padding: 10px 15px; z-index: 1000; text-decoration: none; } .skip-link:focus { top: 10px; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } document.addEventListener(“DOMContentLoaded”, function () { const page = document.querySelector(“.page-container”); if (!page) { console.log(“No .page-container found”); return; } document.addEventListener(“click”, function (event) { const t1 = event.target.closest(“.link-trigger-1”); const t2 = event.target.closest(“.link-trigger-2”); // Click inside link-trigger-1 if (t1) { console.log(“Clicked link-trigger-1 → overflow: clip”); page.style.overflow = “clip”; // if this does nothing in your browser, use “hidden” } // Click inside link-trigger-2 if (t2) { console.log(“Clicked link-trigger-2 → overflow: visible”); page.style.overflow = “visible”; // or “auto”/”hidden” depending on what you want } }); }); (function() { // Configuration var config = { autoplayDelay: 2300, // Time between auto-advances (ms) transitionSpeed: 600 // Slide transition duration (ms) }; // State var isTransitioning = false; var autoplayInterval = null; var track = null; var slides = []; var slideWidth = 0; var currentOffset = 0; var leftBuffer = 2; // Initialize function init() { track = document.getElementById(‘reviewBadgeTrack’); if (!track) return; track.style.visibility = ‘hidden’; slides = Array.from(track.querySelectorAll(‘.review-badge-carousel__slide’)); if (slides.length === 0) { track.style.visibility = ‘visible’; return; } calculateDimensions(); for (var i = 0; i < leftBuffer; i++) { var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); } centerCurrentSlide(false); updateActiveStates(); requestAnimationFrame(function() { track.style.visibility = 'visible'; startAutoplay(); }); window.addEventListener('resize', handleResize); track.addEventListener('click', handleSlideClick); track.parentElement.addEventListener('mouseenter', stopAutoplay); track.parentElement.addEventListener('mouseleave', startAutoplay); } function calculateDimensions() { if (slides.length === 0) return; var firstSlide = slides[0]; var style = getComputedStyle(firstSlide); var width = firstSlide.offsetWidth; var marginLeft = parseFloat(style.marginLeft); var marginRight = parseFloat(style.marginRight); slideWidth = width + marginLeft + marginRight; } function centerCurrentSlide(animate) { var viewportCenter = window.innerWidth / 2; var slideCenter = slideWidth / 2; currentOffset = viewportCenter – slideCenter – (leftBuffer * slideWidth); if (animate) { isTransitioning = true; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; } else { track.style.transition = 'none'; track.offsetHeight; // Force reflow } track.style.transform = 'translateX(' + currentOffset + 'px)'; } function updateActiveStates() { slides.forEach(function(slide, i) { var isVisible = i <= (leftBuffer + 2); if (i === leftBuffer) { slide.classList.add('active'); } else { slide.classList.remove('active'); } slide.style.visibility = isVisible ? 'visible' : 'hidden'; }); } function nextSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; currentOffset -= slideWidth; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(handleTransitionEnd, config.transitionSpeed); } function handleTransitionEnd() { var firstSlide = slides.shift(); slides.push(firstSlide); track.appendChild(firstSlide); currentOffset += slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); isTransitioning = false; } function prevSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); currentOffset -= slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); currentOffset += slideWidth; requestAnimationFrame(function() { track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(function() { isTransitioning = false; }, config.transitionSpeed); }); } function startAutoplay() { stopAutoplay(); autoplayInterval = setInterval(nextSlide, config.autoplayDelay); } function stopAutoplay() { if (autoplayInterval) { clearInterval(autoplayInterval); autoplayInterval = null; } } function handleSlideClick(e) { var slide = e.target.closest('.review-badge-carousel__slide'); if (!slide || isTransitioning) return; var clickedIndex = slides.indexOf(slide); if (clickedIndex === leftBuffer) return; if (clickedIndex === leftBuffer + 1) { nextSlide(); } else if (clickedIndex === leftBuffer – 1) { prevSlide(); } } var resizeTimeout; function handleResize() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { calculateDimensions(); centerCurrentSlide(false); }, 100); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(); function getUrlParams() { const params = new URLSearchParams(window.location.search); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (params.has(param)) { const val = params.get(param); utmParams[param] = val; document.cookie = `${param}=${val}; path=/;`; } }); return utmParams; } function getUtmFromCookies() { const cookies = document.cookie.split(‘; ‘).reduce((acc, cookie) => { const [key, value] = cookie.split(‘=’); acc[key] = value; return acc; }, {}); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (cookies[param]) { utmParams[param] = cookies[param]; } }); return utmParams; } function fillUtmFields() { let utmData = getUrlParams(); if (Object.keys(utmData).length === 0) { utmData = getUtmFromCookies(); } Object.keys(utmData).forEach(key => { const input = document.querySelector(`input[name=”${key}”]`); if (input) { input.value = utmData[key]; } }); } document.addEventListener(“DOMContentLoaded”, fillUtmFields);
Artemis now offers Participate Energy Prepaid Lease.
Learn more →

Design Editor 3.0

Product Updates
January 28th, 2026
Text Link

Fire Setback Mode

Fire Setback Mode takes compliance off your plate. Code-compliant setbacks are applied automatically, with clear categories for pathways, eaves, and ridges. You can easily adjust setback widths to match local AHJ or jurisdiction requirements. This reduces manual errors and catches issues early in the design process. Designs move through review faster, without last-minute fixes.

Text Link

Ground Mount Mode

Ground Mount Mode makes non-rooftop projects just as easy to design. Add and configure ground-mounted systems directly on the canvas, with full control over pier spacing, orientation, and positioning. Entire mounts can be rotated or repositioned as a single unit, saving time on layout adjustments. This streamlines projects where rooftop solar isn’t the right fit. No separate tools or workflows required.

Text Link

Wiring Mode

Wiring Mode gives you clarity without slowing you down. Automatic wiring is applied by default, so electrical connections are visible right away. When a project needs more control, you can switch to manual wiring at any time. This balances speed for standard systems with flexibility for complex designs. Clear wiring layouts improve confidence during review and handoff.

Text Link

Equipment Mode

Equipment Mode brings the full system into view. Add batteries, inverters, main panels, and meters directly into the design and adjust them visually on the canvas. This makes system architecture easy to understand at a glance. Designs feel more complete earlier in the process, helping teams align faster. Equipment decisions can be reviewed and updated without leaving the editor.

Text Link

Larger Parcel Selection

Larger Parcel Selection expands project boundaries up to 80 meters. This makes it easier to capture nearby structures that could impact shading and production. Taller neighboring buildings are now reflected more accurately in modeling. The result is better estimates in dense or urban environments. Fewer assumptions lead to more reliable designs. Larger parcels mean fewer surprises after the site survey.

Text Link
// Initialize Lenis const lenis = new Lenis({ lerp: 0.1, }); // Listen for the scroll event and log the event data lenis.on(‘scroll’, (e) => { console.log(e); }); // Use requestAnimationFrame to continuously update the scroll function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); gsap.registerPlugin(ScrollTrigger); const splitTypes = document.querySelectorAll(‘.scroll-highlight’); splitTypes.forEach((char, i) => { const text = new SplitType(char, { types: [‘chars’, ‘words’] }); gsap.from(text.chars, { scrollTrigger: { trigger: char, start: ‘top 50%’, end: ‘top 10%’, scrub: 1, }, opacity: 0.2, stagger: 0.1, }); }); new WordPlay({ className: “h-2”, // the text element mode: “letter”, // choose between letter or word offset: 20, // offset if revealed by scroll speed: 0.7, delay: 0.015, // stagger delay }); .skip-link { position: absolute; top: -100px; left: 0; background: #000; color: white; padding: 10px 15px; z-index: 1000; text-decoration: none; } .skip-link:focus { top: 10px; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } document.addEventListener(“DOMContentLoaded”, function () { const page = document.querySelector(“.page-container”); if (!page) { console.log(“No .page-container found”); return; } document.addEventListener(“click”, function (event) { const t1 = event.target.closest(“.link-trigger-1”); const t2 = event.target.closest(“.link-trigger-2”); // Click inside link-trigger-1 if (t1) { console.log(“Clicked link-trigger-1 → overflow: clip”); page.style.overflow = “clip”; // if this does nothing in your browser, use “hidden” } // Click inside link-trigger-2 if (t2) { console.log(“Clicked link-trigger-2 → overflow: visible”); page.style.overflow = “visible”; // or “auto”/”hidden” depending on what you want } }); }); (function() { // Configuration var config = { autoplayDelay: 2300, // Time between auto-advances (ms) transitionSpeed: 600 // Slide transition duration (ms) }; // State var isTransitioning = false; var autoplayInterval = null; var track = null; var slides = []; var slideWidth = 0; var currentOffset = 0; var leftBuffer = 2; // Initialize function init() { track = document.getElementById(‘reviewBadgeTrack’); if (!track) return; track.style.visibility = ‘hidden’; slides = Array.from(track.querySelectorAll(‘.review-badge-carousel__slide’)); if (slides.length === 0) { track.style.visibility = ‘visible’; return; } calculateDimensions(); for (var i = 0; i < leftBuffer; i++) { var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); } centerCurrentSlide(false); updateActiveStates(); requestAnimationFrame(function() { track.style.visibility = 'visible'; startAutoplay(); }); window.addEventListener('resize', handleResize); track.addEventListener('click', handleSlideClick); track.parentElement.addEventListener('mouseenter', stopAutoplay); track.parentElement.addEventListener('mouseleave', startAutoplay); } function calculateDimensions() { if (slides.length === 0) return; var firstSlide = slides[0]; var style = getComputedStyle(firstSlide); var width = firstSlide.offsetWidth; var marginLeft = parseFloat(style.marginLeft); var marginRight = parseFloat(style.marginRight); slideWidth = width + marginLeft + marginRight; } function centerCurrentSlide(animate) { var viewportCenter = window.innerWidth / 2; var slideCenter = slideWidth / 2; currentOffset = viewportCenter – slideCenter – (leftBuffer * slideWidth); if (animate) { isTransitioning = true; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; } else { track.style.transition = 'none'; track.offsetHeight; // Force reflow } track.style.transform = 'translateX(' + currentOffset + 'px)'; } function updateActiveStates() { slides.forEach(function(slide, i) { var isVisible = i <= (leftBuffer + 2); if (i === leftBuffer) { slide.classList.add('active'); } else { slide.classList.remove('active'); } slide.style.visibility = isVisible ? 'visible' : 'hidden'; }); } function nextSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; currentOffset -= slideWidth; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(handleTransitionEnd, config.transitionSpeed); } function handleTransitionEnd() { var firstSlide = slides.shift(); slides.push(firstSlide); track.appendChild(firstSlide); currentOffset += slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); isTransitioning = false; } function prevSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); currentOffset -= slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); currentOffset += slideWidth; requestAnimationFrame(function() { track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(function() { isTransitioning = false; }, config.transitionSpeed); }); } function startAutoplay() { stopAutoplay(); autoplayInterval = setInterval(nextSlide, config.autoplayDelay); } function stopAutoplay() { if (autoplayInterval) { clearInterval(autoplayInterval); autoplayInterval = null; } } function handleSlideClick(e) { var slide = e.target.closest('.review-badge-carousel__slide'); if (!slide || isTransitioning) return; var clickedIndex = slides.indexOf(slide); if (clickedIndex === leftBuffer) return; if (clickedIndex === leftBuffer + 1) { nextSlide(); } else if (clickedIndex === leftBuffer – 1) { prevSlide(); } } var resizeTimeout; function handleResize() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { calculateDimensions(); centerCurrentSlide(false); }, 100); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(); function getUrlParams() { const params = new URLSearchParams(window.location.search); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (params.has(param)) { const val = params.get(param); utmParams[param] = val; document.cookie = `${param}=${val}; path=/;`; } }); return utmParams; } function getUtmFromCookies() { const cookies = document.cookie.split(‘; ‘).reduce((acc, cookie) => { const [key, value] = cookie.split(‘=’); acc[key] = value; return acc; }, {}); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (cookies[param]) { utmParams[param] = cookies[param]; } }); return utmParams; } function fillUtmFields() { let utmData = getUrlParams(); if (Object.keys(utmData).length === 0) { utmData = getUtmFromCookies(); } Object.keys(utmData).forEach(key => { const input = document.querySelector(`input[name=”${key}”]`); if (input) { input.value = utmData[key]; } }); } document.addEventListener(“DOMContentLoaded”, fillUtmFields);
Artemis now offers Participate Energy Prepaid Lease.
Learn more →

Design Editor 3.0

Product Updates
January 28th, 2026
Text Link

Toolbar

The Toolbar keeps everything you need within reach. Add roof planes, panels, obstacles, and more with a single click. Common actions are front and center, so there’s less hunting through menus and more designing. It’s built to speed up early layout creation and get you from a blank canvas to a complete system faster. Less friction means better focus on accuracy.

Text Link

Full Canvas Control

Full Canvas Control puts editing exactly where it should be: on the canvas. Drag, resize, rotate, and adjust components without switching tools or views. Every change is immediately visible, making reviews and collaboration easier. The experience feels fluid and intuitive, even during fast iterations. Designers can move quickly without losing precision.

Text Link

Roof Plane Enhancements

Roof plane creation is now faster and more precise. Dotted line guides help with placement and alignment, reducing guesswork during setup. Azimuth snapping lets you orient roof planes instantly by clicking the directional arrow. Height adjustments make it easier to model multi-level homes and complex roof structures. These improvements reduce manual cleanup later.

Text Link

Obstacle Modeling Improvements

Obstacle modeling is now more flexible and more realistic. Create circular, rectangular, or polygonal obstacles directly on the roof. Adjust heights to accurately represent vents, skylights, and rooftop equipment. Better obstacle modeling leads to more accurate shading and panel placement. That means fewer revisions down the line. Designs feel cleaner, and production estimates are easier to trust.

Text Link

Advanced Tree Modeling

Tree modeling now supports both round and conical shapes for more realistic canopies. This makes it easier to represent how different tree types actually affect solar access. Designers can better match on-site vegetation without manual workarounds. Improved tree geometry feeds directly into more accurate shading calculations. Fewer adjustments are needed later.

Text Link

Production Engine V2

Production Engine V2 brings a smarter approach to accuracy. A new shading algorithm considers additional factors like state-specific default losses, inverter efficiency, and DC/AC ratio. These improvements produce estimates that more closely reflect real-world performance. Designs come together faster, with fewer assumptions. Teams can trust early-stage designs with less manual validation.

// Initialize Lenis const lenis = new Lenis({ lerp: 0.1, }); // Listen for the scroll event and log the event data lenis.on(‘scroll’, (e) => { console.log(e); }); // Use requestAnimationFrame to continuously update the scroll function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); gsap.registerPlugin(ScrollTrigger); const splitTypes = document.querySelectorAll(‘.scroll-highlight’); splitTypes.forEach((char, i) => { const text = new SplitType(char, { types: [‘chars’, ‘words’] }); gsap.from(text.chars, { scrollTrigger: { trigger: char, start: ‘top 50%’, end: ‘top 10%’, scrub: 1, }, opacity: 0.2, stagger: 0.1, }); }); new WordPlay({ className: “h-2”, // the text element mode: “letter”, // choose between letter or word offset: 20, // offset if revealed by scroll speed: 0.7, delay: 0.015, // stagger delay }); .skip-link { position: absolute; top: -100px; left: 0; background: #000; color: white; padding: 10px 15px; z-index: 1000; text-decoration: none; } .skip-link:focus { top: 10px; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } document.addEventListener(“DOMContentLoaded”, function () { const page = document.querySelector(“.page-container”); if (!page) { console.log(“No .page-container found”); return; } document.addEventListener(“click”, function (event) { const t1 = event.target.closest(“.link-trigger-1”); const t2 = event.target.closest(“.link-trigger-2”); // Click inside link-trigger-1 if (t1) { console.log(“Clicked link-trigger-1 → overflow: clip”); page.style.overflow = “clip”; // if this does nothing in your browser, use “hidden” } // Click inside link-trigger-2 if (t2) { console.log(“Clicked link-trigger-2 → overflow: visible”); page.style.overflow = “visible”; // or “auto”/”hidden” depending on what you want } }); }); (function() { // Configuration var config = { autoplayDelay: 2300, // Time between auto-advances (ms) transitionSpeed: 600 // Slide transition duration (ms) }; // State var isTransitioning = false; var autoplayInterval = null; var track = null; var slides = []; var slideWidth = 0; var currentOffset = 0; var leftBuffer = 2; // Initialize function init() { track = document.getElementById(‘reviewBadgeTrack’); if (!track) return; track.style.visibility = ‘hidden’; slides = Array.from(track.querySelectorAll(‘.review-badge-carousel__slide’)); if (slides.length === 0) { track.style.visibility = ‘visible’; return; } calculateDimensions(); for (var i = 0; i < leftBuffer; i++) { var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); } centerCurrentSlide(false); updateActiveStates(); requestAnimationFrame(function() { track.style.visibility = 'visible'; startAutoplay(); }); window.addEventListener('resize', handleResize); track.addEventListener('click', handleSlideClick); track.parentElement.addEventListener('mouseenter', stopAutoplay); track.parentElement.addEventListener('mouseleave', startAutoplay); } function calculateDimensions() { if (slides.length === 0) return; var firstSlide = slides[0]; var style = getComputedStyle(firstSlide); var width = firstSlide.offsetWidth; var marginLeft = parseFloat(style.marginLeft); var marginRight = parseFloat(style.marginRight); slideWidth = width + marginLeft + marginRight; } function centerCurrentSlide(animate) { var viewportCenter = window.innerWidth / 2; var slideCenter = slideWidth / 2; currentOffset = viewportCenter – slideCenter – (leftBuffer * slideWidth); if (animate) { isTransitioning = true; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; } else { track.style.transition = 'none'; track.offsetHeight; // Force reflow } track.style.transform = 'translateX(' + currentOffset + 'px)'; } function updateActiveStates() { slides.forEach(function(slide, i) { var isVisible = i <= (leftBuffer + 2); if (i === leftBuffer) { slide.classList.add('active'); } else { slide.classList.remove('active'); } slide.style.visibility = isVisible ? 'visible' : 'hidden'; }); } function nextSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; currentOffset -= slideWidth; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(handleTransitionEnd, config.transitionSpeed); } function handleTransitionEnd() { var firstSlide = slides.shift(); slides.push(firstSlide); track.appendChild(firstSlide); currentOffset += slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); isTransitioning = false; } function prevSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); currentOffset -= slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); currentOffset += slideWidth; requestAnimationFrame(function() { track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(function() { isTransitioning = false; }, config.transitionSpeed); }); } function startAutoplay() { stopAutoplay(); autoplayInterval = setInterval(nextSlide, config.autoplayDelay); } function stopAutoplay() { if (autoplayInterval) { clearInterval(autoplayInterval); autoplayInterval = null; } } function handleSlideClick(e) { var slide = e.target.closest('.review-badge-carousel__slide'); if (!slide || isTransitioning) return; var clickedIndex = slides.indexOf(slide); if (clickedIndex === leftBuffer) return; if (clickedIndex === leftBuffer + 1) { nextSlide(); } else if (clickedIndex === leftBuffer – 1) { prevSlide(); } } var resizeTimeout; function handleResize() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { calculateDimensions(); centerCurrentSlide(false); }, 100); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(); function getUrlParams() { const params = new URLSearchParams(window.location.search); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (params.has(param)) { const val = params.get(param); utmParams[param] = val; document.cookie = `${param}=${val}; path=/;`; } }); return utmParams; } function getUtmFromCookies() { const cookies = document.cookie.split(‘; ‘).reduce((acc, cookie) => { const [key, value] = cookie.split(‘=’); acc[key] = value; return acc; }, {}); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (cookies[param]) { utmParams[param] = cookies[param]; } }); return utmParams; } function fillUtmFields() { let utmData = getUrlParams(); if (Object.keys(utmData).length === 0) { utmData = getUtmFromCookies(); } Object.keys(utmData).forEach(key => { const input = document.querySelector(`input[name=”${key}”]`); if (input) { input.value = utmData[key]; } }); } document.addEventListener(“DOMContentLoaded”, fillUtmFields);

Product Manager (First PM)

Company: Artemis 

Location: Remote 

Stage: Venture-backed, millions in ARR, high growth

The opportunity

At Artemis, we are building the software backbone for the modern, distributed energy grid. Solar, batteries, EVs, and home energy are reshaping how power is generated and managed, and the industry’s tools have not kept up. We are changing that.

We have gone from zero to millions in ARR by moving fast, challenging assumptions, and staying deeply focused on real customer problems. Now, we are hiring our first Product Manager to help us scale that momentum and shape how product is built at Artemis.

This role is for someone who wants to be early, close to the action, and deeply influential.

What you’ll do

  • Own product discovery, prioritization, and delivery across Artemis.
  • Work directly with customers, engineers, designers, and leadership to define what matters most.
  • Translate ambiguity into clear product direction without adding unnecessary process.
  • Partner daily with a team of approximately 14 engineers, 3 designers, and 10 AI, computer vision, and GIS specialists.
  • Help scale product velocity as we move further into enterprise and more complex use cases.
  • Set the foundation for product thinking and execution as Artemis grows.

Who you are

  • You thrive in early-stage environments where things are moving fast and not fully defined.
  • You are scrappy, resourceful, and biased toward action.
  • You challenge assumptions and push for better answers.
  • You care deeply about doing the right thing for customers and teammates.
  • You are comfortable owning outcomes, not just requirements.
  • You communicate clearly with both technical and non-technical teams.

Background we prefer

  • Experience at a high-growth startup, ideally in an early or scaling phase.
  • Background in B2B or B2B2C software.
  • An engineering background or the ability to speak engineering fluently and work closely with technical teams.

Our values

  • Move fast.
  • SLLS (Stop, Look, Listen, and Smell).
  • Challenge assumptions.
  • Be scrappy.
  • Always be Learning.
  • Do the Right Thing.

These are not slogans. They show up in how we build, how we ship, and how we treat people.

Why Artemis

  • You will define the product function from day one.
  • ou will work on one of the most important infrastructure transitions of our time.
  • You will have real ownership and meaningful impact.
  • You will build alongside world-class engineers, designers, and AI researchers.

How to apply

Apply via our application link, or email Walid@artemispower.com directly with a short note on why this role excites you.

Apply Now

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Artemis now offers Participate Energy Prepaid Lease.
Learn more →
// Initialize Lenis const lenis = new Lenis({ lerp: 0.1, }); // Listen for the scroll event and log the event data lenis.on(‘scroll’, (e) => { console.log(e); }); // Use requestAnimationFrame to continuously update the scroll function raf(time) { lenis.raf(time); requestAnimationFrame(raf); } requestAnimationFrame(raf); gsap.registerPlugin(ScrollTrigger); const splitTypes = document.querySelectorAll(‘.scroll-highlight’); splitTypes.forEach((char, i) => { const text = new SplitType(char, { types: [‘chars’, ‘words’] }); gsap.from(text.chars, { scrollTrigger: { trigger: char, start: ‘top 50%’, end: ‘top 10%’, scrub: 1, }, opacity: 0.2, stagger: 0.1, }); }); new WordPlay({ className: “h-2”, // the text element mode: “letter”, // choose between letter or word offset: 20, // offset if revealed by scroll speed: 0.7, delay: 0.015, // stagger delay }); .skip-link { position: absolute; top: -100px; left: 0; background: #000; color: white; padding: 10px 15px; z-index: 1000; text-decoration: none; } .skip-link:focus { top: 10px; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; } document.addEventListener(“DOMContentLoaded”, function () { const page = document.querySelector(“.page-container”); if (!page) { console.log(“No .page-container found”); return; } document.addEventListener(“click”, function (event) { const t1 = event.target.closest(“.link-trigger-1”); const t2 = event.target.closest(“.link-trigger-2”); // Click inside link-trigger-1 if (t1) { console.log(“Clicked link-trigger-1 → overflow: clip”); page.style.overflow = “clip”; // if this does nothing in your browser, use “hidden” } // Click inside link-trigger-2 if (t2) { console.log(“Clicked link-trigger-2 → overflow: visible”); page.style.overflow = “visible”; // or “auto”/”hidden” depending on what you want } }); }); (function() { // Configuration var config = { autoplayDelay: 2300, // Time between auto-advances (ms) transitionSpeed: 600 // Slide transition duration (ms) }; // State var isTransitioning = false; var autoplayInterval = null; var track = null; var slides = []; var slideWidth = 0; var currentOffset = 0; var leftBuffer = 2; // Initialize function init() { track = document.getElementById(‘reviewBadgeTrack’); if (!track) return; track.style.visibility = ‘hidden’; slides = Array.from(track.querySelectorAll(‘.review-badge-carousel__slide’)); if (slides.length === 0) { track.style.visibility = ‘visible’; return; } calculateDimensions(); for (var i = 0; i < leftBuffer; i++) { var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); } centerCurrentSlide(false); updateActiveStates(); requestAnimationFrame(function() { track.style.visibility = 'visible'; startAutoplay(); }); window.addEventListener('resize', handleResize); track.addEventListener('click', handleSlideClick); track.parentElement.addEventListener('mouseenter', stopAutoplay); track.parentElement.addEventListener('mouseleave', startAutoplay); } function calculateDimensions() { if (slides.length === 0) return; var firstSlide = slides[0]; var style = getComputedStyle(firstSlide); var width = firstSlide.offsetWidth; var marginLeft = parseFloat(style.marginLeft); var marginRight = parseFloat(style.marginRight); slideWidth = width + marginLeft + marginRight; } function centerCurrentSlide(animate) { var viewportCenter = window.innerWidth / 2; var slideCenter = slideWidth / 2; currentOffset = viewportCenter – slideCenter – (leftBuffer * slideWidth); if (animate) { isTransitioning = true; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; } else { track.style.transition = 'none'; track.offsetHeight; // Force reflow } track.style.transform = 'translateX(' + currentOffset + 'px)'; } function updateActiveStates() { slides.forEach(function(slide, i) { var isVisible = i <= (leftBuffer + 2); if (i === leftBuffer) { slide.classList.add('active'); } else { slide.classList.remove('active'); } slide.style.visibility = isVisible ? 'visible' : 'hidden'; }); } function nextSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; currentOffset -= slideWidth; track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(handleTransitionEnd, config.transitionSpeed); } function handleTransitionEnd() { var firstSlide = slides.shift(); slides.push(firstSlide); track.appendChild(firstSlide); currentOffset += slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); isTransitioning = false; } function prevSlide() { if (isTransitioning || slides.length === 0) return; isTransitioning = true; var lastSlide = slides.pop(); slides.unshift(lastSlide); track.insertBefore(lastSlide, track.firstChild); currentOffset -= slideWidth; track.style.transition = 'none'; track.offsetHeight; // Force reflow track.style.transform = 'translateX(' + currentOffset + 'px)'; updateActiveStates(); currentOffset += slideWidth; requestAnimationFrame(function() { track.style.transition = 'transform ' + config.transitionSpeed + 'ms ease'; track.style.transform = 'translateX(' + currentOffset + 'px)'; setTimeout(function() { isTransitioning = false; }, config.transitionSpeed); }); } function startAutoplay() { stopAutoplay(); autoplayInterval = setInterval(nextSlide, config.autoplayDelay); } function stopAutoplay() { if (autoplayInterval) { clearInterval(autoplayInterval); autoplayInterval = null; } } function handleSlideClick(e) { var slide = e.target.closest('.review-badge-carousel__slide'); if (!slide || isTransitioning) return; var clickedIndex = slides.indexOf(slide); if (clickedIndex === leftBuffer) return; if (clickedIndex === leftBuffer + 1) { nextSlide(); } else if (clickedIndex === leftBuffer – 1) { prevSlide(); } } var resizeTimeout; function handleResize() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function() { calculateDimensions(); centerCurrentSlide(false); }, 100); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })(); function getUrlParams() { const params = new URLSearchParams(window.location.search); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (params.has(param)) { const val = params.get(param); utmParams[param] = val; document.cookie = `${param}=${val}; path=/;`; } }); return utmParams; } function getUtmFromCookies() { const cookies = document.cookie.split(‘; ‘).reduce((acc, cookie) => { const [key, value] = cookie.split(‘=’); acc[key] = value; return acc; }, {}); let utmParams = {}; const list = [‘utm_source’, ‘utm_medium’, ‘utm_campaign’, ‘utm_term’, ‘utm_content’]; list.forEach(param => { if (cookies[param]) { utmParams[param] = cookies[param]; } }); return utmParams; } function fillUtmFields() { let utmData = getUrlParams(); if (Object.keys(utmData).length === 0) { utmData = getUtmFromCookies(); } Object.keys(utmData).forEach(key => { const input = document.querySelector(`input[name=”${key}”]`); if (input) { input.value = utmData[key]; } }); } document.addEventListener(“DOMContentLoaded”, fillUtmFields);

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!