Crie uma Impressora 3D CSS que Realmente Imprime!

Por algum tempo, tenho criado essas cenas 3D com CSS apenas por diversão — geralmente durante minha transmissão ao vivo.

Cada demonstração é uma oportunidade para tentar algo diferente ou descobrir maneiras de fazer coisas com CSS. Uma coisa que frequentemente faço é pegar sugestões sobre o que devemos tentar criar na transmissão. Uma sugestão recente foi uma impressora que imprime em “3D”. E aqui está o que eu montei!

Criando Coisas 3D com CSS

I’ve written about making things 3D with CSS before. The general gist is that most scenes are a composition of cuboids.

Para criar um cuboide, podemos usar transformações CSS para posicionar os lados de um cuboide — a propriedade mágica sendo transform-style. Definindo isso como preserve-3d nos permite transformar elementos na terceira dimensão:

* {
  transform-style: preserve-3d;
}

Uma vez que você cria algumas dessas cenas, começa a aprender maneiras de acelerar o processo. Gosto de usar o Pug como pré-processador HTML. A capacidade de mixins me permite criar cuboides de forma mais rápida. Os exemplos de marcação deste artigo utilizam o Pug. Mas para cada demonstração CodePen, você pode usar a opção “Ver HTML Compilado” para ver a saída HTML:

mixin cuboid()
  .cuboid(class!=attributes.class)
    - let s = 0
    while s < 6
      .cuboid__side
      - s++

Usar +cuboid()(class="printer__top") produz isto:

<div class="cuboid printer__top">
  <div class="cuboid__side"></div>
  <div class="cuboid__side"></div>
  <div class="cuboid__side"></div>
  <div class="cuboid__side"></div>
  <div class="cuboid__side"></div>
  <div class="cuboid__side"></div>
</div>

Então, eu tenho um bloco de CSS que utilizo para dispor os cuboides. A alegria aqui é que podemos aproveitar propriedades CSS personalizadas para definir as propriedades de um cuboide (como mostrado no vídeo acima):

.cuboid {
  // Defaults
  --width: 15;
  --height: 10;
  --depth: 4;
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform-style: preserve-3d;
  position: absolute;
  font-size: 1rem;
  transform: translate3d(0, 0, 5vmin);
}
.cuboid > div:nth-of-type(1) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
}
.cuboid > div:nth-of-type(2) {
  height: calc(var(--height) * 1vmin);
  width: 100%;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(180deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(3) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(4) {
  height: calc(var(--height) * 1vmin);
  width: calc(var(--depth) * 1vmin);
  transform: translate(-50%, -50%) rotateX(-90deg) rotateY(-90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(5) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * 1vmin));
  position: absolute;
  top: 50%;
  left: 50%;
}
.cuboid > div:nth-of-type(6) {
  height: calc(var(--depth) * 1vmin);
  width: calc(var(--width) * 1vmin);
  transform: translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * -1vmin)) rotateX(180deg);
  position: absolute;
  top: 50%;
  left: 50%;
}

Usando propriedades personalizadas, podemos controlar várias características dos cuboides, e assim por diante:

  • --width: a largura de um cuboide no plano
  • --height: a altura de um cuboide no plano
  • --depth: a profundidade de um cuboide no plano
  • --x: a posição X no plano
  • --y: a posição Y no plano

Isso não é muito impressionante até colocarmos o cuboide em uma cena e rotacioná-lo. Mais uma vez, utilizo propriedades personalizadas para manipular a cena enquanto trabalho na criação de algo. Dat.GUI é extremamente útil aqui.

Se você inspecionar a demonstração, usando o painel de controle atualiza as propriedades CSS personalizadas na cena. Essa limitação das propriedades CSS personalizadas economiza muito código repetido e mantém as coisas DRY.

Mais de Uma Maneira

Tal como muitas coisas no CSS, há mais de uma maneira de fazê-lo. Muitas vezes, você pode compor uma cena a partir de cubóides e posicionar as coisas conforme e quando precisar. No entanto, pode ficar complicado de gerenciar. Muitas vezes, há necessidade de agrupar coisas ou adicionar algum tipo de container.

Considere este exemplo em que a cadeira é sua própria subcena que pode ser movida.

Muitos exemplos recentes não são tão complexos. Tenho recorrido à extrusão. Isso significa que posso mapear o que estou fazendo em elementos 2D. Por exemplo, aqui está um helicóptero que criei recentemente:

.helicopter
  .helicopter__rotor
  .helicopter__cockpit
    .helicopter__base-light
    .helicopter__chair
      .helicopter__chair-back
      .helicopter__chair-bottom
    .helicopter__dashboard
  .helicopter__tail
  .helicopter__fin
    .helicopter__triblade
    .helicopter__tail-light
  .helicopter__stabilizer
  .helicopter__skids
    .helicopter__skid--left.helicopter__skid
    .helicopter__skid--right.helicopter__skid
  .helicopter__wing
    .helicopter__wing-light.helicopter__wing-light--left
    .helicopter__wing-light.helicopter__wing-light--right
  .helicopter__launchers
    .helicopter__launcher.helicopter__launcher--left
    .helicopter__launcher.helicopter__launcher--right
  .helicopter__blades

Em seguida, podemos colocar cubóides em todos os containers usando o mixin. Em seguida, aplique uma “espessura” necessária a cada cubóide. A espessura é determinada por propriedades personalizadas delimitadas. Este demo alterna a propriedade --thickness para os cubóides que compõem o helicóptero. Isso dá uma ideia do que parecia o mapeamento 2D para começar.

Esse é o cerne de como proceder para criar coisas 3D com CSS. Indagar no código revelará alguns truques com certeza. Mas, em geral, monte uma cena, preencha com cubóides e colora os cubóides. Muitas vezes, você desejará diferentes tons de uma cor para que possamos diferenciar os lados de um cubóide. Quaisquer detalhes adicionais são coisas que podemos adicionar a um lado do cubóide ou transformações que podemos aplicar a um cubóide. Por exemplo, girando e movendo no eixo Z.

Vamos considerar um exemplo simplificado:

.scene
  .extrusion
    +cuboid()(class="extrusion__cuboid")

O novo CSS para criar um cubóide com extrusão poderia parecer com isso. Observe como estamos incluindo propriedades personalizadas delimitadas para a cor de cada lado também. Seria prudente adicionar alguns valores padrão sob o :root aqui ou valores de fallback:

.cuboid {
  width: 100%;
  height: 100%;
  position: relative;
}
.cuboid__side:nth-of-type(1) {
  background: var(--shade-one);
  height: calc(var(--thickness) * 1vmin);
  width: 100%;
  position: absolute;
  top: 0;
  transform: translate(0, -50%) rotateX(90deg);
}
.cuboid__side:nth-of-type(2) {
  background: var(--shade-two);
  height: 100%;
  width: calc(var(--thickness) * 1vmin);
  position: absolute;
  top: 50%;
  right: 0;
  transform: translate(50%, -50%) rotateY(90deg);
}
.cuboid__side:nth-of-type(3) {
  background: var(--shade-three);
  width: 100%;
  height: calc(var(--thickness) * 1vmin);
  position: absolute;
  bottom: 0;
  transform: translate(0%, 50%) rotateX(90deg);
}
.cuboid__side:nth-of-type(4) {
  background: var(--shade-two);
  height: 100%;
  width: calc(var(--thickness) * 1vmin);
  position: absolute;
  left: 0;
  top: 50%;
  transform: translate(-50%, -50%) rotateY(90deg);
}
.cuboid__side:nth-of-type(5) {
  background: var(--shade-three);
  height: 100%;
  width: 100%;
  transform: translate3d(0, 0, calc(var(--thickness) * 0.5vmin));
  position: absolute;
  top: 0;
  left: 0;
}
.cuboid__side:nth-of-type(6) {
  background: var(--shade-one);
  height: 100%;
  width: 100%;
  transform: translate3d(0, 0, calc(var(--thickness) * -0.5vmin)) rotateY(180deg);
  position: absolute;
  top: 0;
  left: 0;
}

Optamos por três tons para este exemplo. Mas às vezes, você pode precisar de mais. Esta demonstração junta tudo isso, mas permite alterar propriedades personalizadas em escopo. O valor de “espessura” mudará a extrusão do cuboide. As transformações e dimensões afetarão o elemento contido com a classe “extrusão”.

Montagem de uma Impressora

Para começar, podemos montar todos os pedaços necessários. Com prática, isso se torna mais óbvio. Mas a regra geral é tentar visualizar tudo como caixas. Isso lhe dá uma boa ideia de como dividir algo:

.scene
  .printer
    .printer__side.printer__side--left
    .printer__side.printer__side--right
    .printer__tray.printer__tray--bottom
    .printer__tray.printer__tray--top
    .printer__top
    .printer__back

Veja se consegue visualizar o que estamos tentando alcançar aqui. As duas peças laterais deixam uma lacuna no meio. Então, temos um cuboide que se estende pelo topo e outro que preenche a parte de trás. Depois, dois cuboides para compor a bandeja de papel.

Uma vez chegando a esse estágio, é questão de preencher os cuboides, o que se parece com isto:

.scene
  .printer
    .printer__side.printer__side--left
      +cuboid()(class="cuboid--side")
    .printer__side.printer__side--right
      +cuboid()(class="cuboid--side")
    .printer__tray.printer__tray--bottom
      +cuboid()(class="cuboid--tray")
    .printer__tray.printer__tray--top
      +cuboid()(class="cuboid--tray")
    .printer__top
      +cuboid()(class="cuboid--top")
    .printer__back
      +cuboid()(class="cuboid--back")      

Observe como somos capazes de reutilizar os nomes de classe, como cuboid--side. Esses cuboides provavelmente terão a mesma espessura e usarão as mesmas cores. Sua posição e tamanho são ditados pelo elemento contido.

Juntando tudo, podemos obter algo assim.

A explosão da demonstração mostra os diferentes cuboides que compõem a impressora. Se você desativar a extrusão, poderá ver os elementos contidos planos.

Adicionando Detalhes

Agora, você deve ter notado que há mais detalhes do que simplesmente adicionar cores a cada lado. E isso se resume a encontrar maneiras de adicionar detalhes extras. Temos diferentes opções dependendo do que queremos adicionar.

Se for uma imagem ou algumas mudanças básicas de cor, podemos usar o `background-image` para criar camadas de gradientes, e assim por diante.

Por exemplo, o topo da impressora tem detalhes, bem como a abertura da impressora. Este código aborda o lado superior do cubóide superior. O gradiente lida com a abertura da impressora e os detalhes:

.cuboid--top {
  --thickness: var(--depth);
  --shade-one: linear-gradient(#292929, #292929) 100% 50%/14% 54% no-repeat, linear-gradient(var(--p-7), var(--p-7)) 40% 50%/12% 32% no-repeat, linear-gradient(var(--p-7), var(--p-7)) 30% 50%/2% 12% no-repeat, linear-gradient(var(--p-3), var(--p-3)) 0% 50%/66% 50% no-repeat, var(--p-1);
}

Para o logotipo do urso, poderíamos usar um `background-image` ou até mesmo recorrer a um pseudo-elemento e posicioná-lo:

.cuboid--top > div:nth-of-type(1):after {
  content: '';
  position: absolute;
  top: 7%;
  left: 10%;
  height: calc(var(--depth) * 0.12vmin);
  width: calc(var(--depth) * 0.12vmin);
  background: url("https://assets.codepen.io/605876/avatar.png");
  background-size: cover;
  transform: rotate(90deg);
  filter: grayscale(0.5);
}

Se precisarmos adicionar detalhes mais extensos, provavelmente teremos que sair do uso do nosso mixin de cubóide. Por exemplo, o topo da nossa impressora terá uma tela de visualização usando um elemento `img`:

.printer__top
  .cuboid.cuboid--top
    .cuboid__side
    .cuboid__side
    .cuboid__side
    .cuboid__side
      .screen
        .screen__preview
          img.screen__preview-img
    .cuboid__side
    .cuboid__side

Adicione mais alguns detalhes e estaremos prontos para colocar papel na mistura!

Jornada do Papel

O que é uma impressora sem papel? Queremos animar algum papel voando para dentro da impressora e sendo ejetado do outro lado. Algo como este demo: clique em qualquer lugar para ver um pedaço de papel alimentado na impressora e impresso.

Podemos adicionar um bloco de papel à cena com um cubóide e, em seguida, usar um elemento separado para atuar como uma única folha de papel:

.paper-stack.paper-stack--bottom
  +cuboid()(class="cuboid--paper")
.paper-stack.paper-stack--top
  .cuboid.cuboid--paper
    .cuboid__side
      .paper
        .paper__flyer
    .cuboid__side
    .cuboid__side
    .cuboid__side
    .cuboid__side
    .cuboid__side

Mas animar o papel voando para dentro da impressora envolve algumas tentativas e erros. É prudente brincar com diferentes transformações no inspetor do DevTools. Esta é uma boa maneira de ver como as coisas ficarão. Muitas vezes, também é mais fácil usar elementos envoltórios. Usamos o elemento `.paper` para fazer a transferência e, em seguida, usamos `.paper__flyer` para animar a alimentação do papel:

:root {
  --load-speed: 2;
}

.paper-stack--top .cuboid--paper .paper {
  animation: transfer calc(var(--load-speed) * 0.5s) ease-in-out forwards;
}
.paper-stack--top .cuboid--paper .paper__flyer {
  animation: fly calc(var(--load-speed) * 0.5s) ease-in-out forwards;
}
.paper-stack--top .cuboid--paper .paper__flyer:after {
  animation: feed calc(var(--load-speed) * 0.5s) calc(var(--load-speed) * 0.5s) forwards;
}

@keyframes transfer {
  to {
    transform: translate(0, -270%) rotate(22deg);
  }
}

@keyframes feed {
  to {
    transform: translate(100%, 0);
  }
}

@keyframes fly {
  0% {
    transform: translate3d(0, 0, 0) rotateY(0deg) translate(0, 0);
  }
  50% {
    transform: translate3d(140%, 0, calc(var(--height) * 1.2)) rotateY(-75deg) translate(180%, 0);
  }
  100% {
    transform: translate3d(140%, 0, var(--height)) rotateY(-75deg) translate(0%, 0) rotate(-180deg);
  }
}

Você notará que há bastante uso de calc ali. Para compor a linha do tempo da animação, podemos utilizar propriedades CSS personalizadas. Referenciando uma propriedade, podemos calcular os atrasos corretos para cada animação na cadeia. O papel é transferido e voa ao mesmo tempo. Uma animação lida com o movimento do container, outra lida com a rotação do papel. Uma vez que essas animações terminam, o papel é alimentado na impressora com a animação feed. O atraso da animação é igual à duração das duas primeiras animações que funcionam ao mesmo tempo.

Execute este demo onde eu colori os elementos do container em vermelho e verde. Fazemos uso do pseudo-elemento de .paper__flyer para representar o pedaço de papel. Mas os elementos do container fazem o trabalho pesado:

Você pode estar se perguntando quando o papel sai do outro lado. Mas, na verdade, o papel não é o mesmo elemento durante todo o processo. Usamos um elemento para entrar na impressora. E outro elemento para o papel quando ele voa para fora da impressora. Este é outro exemplo em que elementos extras facilitam nossa vida.

O papel usa mais de um elemento para fazer o loop, e então o papel é posicionado na borda desse elemento. Executando este demo com mais elementos de container coloridos mostra como isso está funcionando.

Mais uma vez, isso requer um pouco de tentativa e erro, bem como pensar sobre como podemos aproveitar o uso de elementos de container. Ter um container com um transform-origin offset nos permite criar o loop.

Impressão

Tudo está pronto. Agora é uma questão de realmente imprimir algo. Para fazer isso, vamos adicionar um formulário que permita aos usuários inserir a URL de uma imagem:

form.customer-form
  label(for="print") Print URL
  input#print(type='url' required placeholder="URL for Printing")
  input(type="submit" value="Print")

Com algum estilo, obtemos algo assim.

O comportamento nativo dos formulários e o uso de required e type="url" significa que só aceitamos uma URL. Poderíamos ir mais longe com um pattern e verificar certos tipos de imagens. Mas algumas URLs aleatórias boas para imagens não incluem o tipo de imagem, como https://source.unsplash.com/random.

Enviar nosso formulário não se comporta como queremos, e também a animação de impressão é executada uma vez na carga. Uma maneira de contornar isso seria executar a animação apenas quando uma determinada classe é aplicada à impressora.

Quando submetemos o formulário, podemos fazer uma solicitação para a URL e, em seguida, definir o src para as imagens em nossa cena — uma imagem sendo a pré-visualização na tela da impressora, a outra sendo uma imagem em um lado do papel. De fato, ao imprimir, vamos adicionar um novo elemento para cada pedaço de papel impresso. Dessa forma, cada impressão parece ser adicionada a uma pilha. Podemos remover o pedaço de papel que temos na carga.

Vamos começar tratando a submissão do formulário. Vamos impedir o evento padrão e chamar uma função PROCESS:

const PRINT = e => {
  e.preventDefault()
  PROCESS()
}

const PRINT_FORM = document.querySelector('form')
PRINT_FORM.addEventListener('submit', PRINT)

Esta função lidará com a solicitação para a nossa fonte de imagem:

let printing = false

const PREVIEW = document.querySelector('img.screen__preview-img')
const SUBMIT = document.querySelector('[type="submit"]')
const URL_INPUT = document.querySelector('[type="url"]')

const PROCESS = async () => {
  if (printing) return
  printing = true
  SUBMIT.disabled = true
  const res = await fetch(URL_INPUT.value)
  PREVIEW.src = res.url
  URL_INPUT.value = ''
}

Também definimos uma variável printing como true, que usaremos para rastrear o estado atual e desabilitar o botão do formulário.

Por que fazemos uma solicitação para a imagem em vez de definir diretamente na imagem? Queremos uma URL absoluta para uma imagem. Se usarmos a URL da “Unsplash” mencionada acima e a compartilharmos entre as imagens, isso pode não funcionar. Isso porque podemos enfrentar situações em que diferentes imagens são exibidas.

Uma vez que temos a fonte da imagem, definimos a fonte da imagem de visualização para essa URL e redefinimos o valor de entrada do formulário.

Para acionar a animação, podemos interagir com o evento “load” de nossa imagem de visualização. Quando o evento é acionado, criamos um novo elemento para a folha de papel a ser impressa e o anexamos ao elemento printer. Ao mesmo tempo, adicionamos uma classe printing ao nosso impressor. Podemos usar isso para acionar a primeira parte da nossa animação de papel:

PREVIEW.addEventListener('load', () => {
  PRINTER.classList.add('printing')
  const PRINT = document.createElement('div')
  PRINT.className = 'printed'
  PRINT.innerHTML = `
    <div class="printed__spinner">
      <div class="printed__paper">
        <div class="printed__papiere">
          <img class="printed__image" src=${PREVIEW.src}/>
        </div>
      </div>
      <div class="printed__paper-back"></div>
    </div>
  `
  PRINTER.appendChild(PRINT)
  // Após um determinado período de tempo, redefinir o estado
  setTimeout(() => {
    printing = false
    SUBMIT.removeAttribute('disabled')
    PRINTER.classList.remove('printing')
  }, 4500)
})

Após um determinado período de tempo, podemos redefinir o estado. Uma abordagem alternativa seria debilitar um evento animationend em ascensão. Mas podemos usar um setTimeout, pois sabemos quanto tempo a animação levará.

No entanto, nossa impressão não está na escala correta. E isso porque precisamos dimensionar a imagem para a folha de papel. Precisamos de um pequeno pedaço de CSS para isso:

.printed__image {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

Também seria legal se as luzes na frente da impressora comunicassem que a impressora está ocupada. Poderíamos ajustar o tom de uma das luzes quando a impressora estiver imprimindo:

.progress-light {
  background: hsla(var(--progress-hue, 104), 80%, 50%);
}
.printing {
  --progress-hue: 10; /* Equivale ao vermelho */
}

Juntando tudo, temos uma “impressora” funcional feita com CSS e um toque de JavaScript.

É isso aí!

Nós demos uma olhada em como podemos fazer uma impressora 3D funcional com CSS, um toque de JavaScript e aproveitando o Pug. Tente adicionar o seguinte link de imagem no campo de URL, ou outro de sua escolha, e experimente!

https://source.unsplash.com/random

Cobrimos um monte de coisas diferentes para conseguir isso, incluindo:

  • como fazer coisas 3D com CSS
  • usando mixins Pug
  • usando propriedades CSS personalizadas com escopo para manter as coisas DRY
  • usando extrusão para criar cenas 3D
  • manipulando formulários com JavaScript
  • compondo cronogramas de animação com propriedades personalizadas

A alegria de criar esses demos é que muitos deles apresentam problemas diferentes a serem superados, como como criar certas formas ou construir certas animações. Geralmente há mais de uma maneira de fazer algo.

Que coisas legais você poderia fazer com CSS 3D? Eu adoraria ver!

Como sempre, obrigado por ler. Quer ver mais? Venha me encontrar no Twitter ou confira minha live stream!

Perguntas Frequentes (FAQs) sobre Impressora 3D CSS

O que é uma Impressora 3D CSS?

A 3D CSS Printer is a unique concept that uses Cascading Style Sheets (CSS), a style sheet language used for describing the look and formatting of a document written in HTML, to create a 3D representation of a printer. This innovative approach allows developers to create interactive and visually appealing web elements that can enhance user experience.

Como funciona uma Impressora 3D CSS?

A 3D CSS Printer works by using CSS properties to create a 3D model of a printer. It uses properties such as transform, perspective, and animation to create the 3D effect. The printer is made up of multiple elements, each styled and positioned to create the overall 3D effect. The animation property is then used to create the printing effect.

Posso personalizar a Impressora 3D CSS?

Sim, você pode personalizar a Impressora 3D CSS. Você pode alterar as cores, o tamanho e até a velocidade da animação. Isso é feito modificando as propriedades CSS da impressora. Por exemplo, você pode alterar a cor modificando a propriedade background-color dos elementos da impressora.

Como posso integrar uma Impressora 3D CSS no meu site?

Integrar uma Impressora 3D CSS no seu site envolve copiar o código CSS e HTML para o código do seu site. Você precisará garantir que o código CSS esteja incluído na seção head do documento HTML e que o código HTML seja colocado onde você deseja que a impressora apareça na sua página web.

É possível animar a Impressora 3D CSS?

Sim, é possível animar a Impressora 3D CSS. A animação é realizada usando a propriedade CSS animation. Essa propriedade permite criar keyframes que definem os estados de início e fim da animação, bem como quaisquer etapas intermediárias.

Quais navegadores suportam a Impressora 3D CSS?

A Impressora 3D CSS deve funcionar em todos os navegadores modernos que suportam as propriedades CSS transform e animation. Isso inclui navegadores como o Google Chrome, Mozilla Firefox, Safari e Microsoft Edge.

Posso usar a Impressora 3D CSS para fins comerciais?

Sim, você pode usar a Impressora 3D CSS para fins comerciais. No entanto, é sempre uma boa ideia verificar os termos de licenciamento de qualquer código que você use para garantir que você esteja em conformidade.

Quais habilidades preciso para criar uma Impressora 3D CSS?

Para criar uma Impressora CSS 3D, você precisa de uma boa compreensão de HTML e CSS. Você deve estar familiarizado com propriedades CSS como transform, perspective e animation. Conhecimento básico de modelagem 3D também pode ser útil, mas não é necessário.

Posso usar JavaScript com a Impressora CSS 3D?

Sim, você pode usar JavaScript com a Impressora CSS 3D. Embora a impressora possa ser criada usando apenas CSS, o JavaScript pode ser usado para adicionar interatividade, como iniciar ou parar a animação com base nas ações do usuário.

Existe algum recurso para aprender mais sobre a Impressora CSS 3D?

Existem muitos recursos online para aprender mais sobre a Impressora CSS 3D. Sites como SitePoint, CSS-Tricks e MDN Web Docs possuem tutoriais e guias extensivos sobre animações CSS e transformações 3D. O YouTube também possui muitos tutoriais em vídeo sobre o assunto.

Source:
https://www.sitepoint.com/3d-css-printer/