shopic 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,46 +16,75 @@ is public even though this repository is not — that is the price of a free CDN
16
16
 
17
17
  ```bash
18
18
  pnpm install
19
- pnpm dev
19
+ pnpm dev # watch + rebuild; also serves dist/ on http://localhost:3000
20
+ pnpm check # tsc
21
+ pnpm lint # eslint + prettier
20
22
  ```
21
23
 
22
- `pnpm dev` serves the bundle at `http://localhost:3000` with live reload.
24
+ `pnpm dev` is for building and type-checking while you work. It is **not** a way
25
+ to preview against the live site — see below.
23
26
 
24
- Put this in **Site Settings Custom Code Footer** once, and leave it there. It
25
- loads the CDN build for everyone, and the local build only for a browser you have
26
- flipped into dev mode:
27
+ The site loads the bundle from jsDelivr. One line in
28
+ **Site Settings Custom Code Footer**, and that is the whole integration:
27
29
 
28
30
  ```html
29
- <script>
30
- (() => {
31
- const PROD = 'https://cdn.jsdelivr.net/npm/shopic@0.0.1/dist/index.js';
32
- const DEV = 'http://localhost:3000/index.js';
33
-
34
- const load = (src, fallback) => {
35
- const s = document.createElement('script');
36
- s.src = src;
37
- if (fallback) s.onerror = fallback;
38
- document.head.appendChild(s);
39
- };
40
-
41
- if (localStorage.getItem('shopic-dev') === 'on') load(DEV, () => load(PROD));
42
- else load(PROD);
43
- })();
44
- </script>
31
+ <script src="https://cdn.jsdelivr.net/npm/shopic@0.0.2/dist/index.js"></script>
45
32
  ```
46
33
 
47
- Flip it on in the console on the staging domain, once:
34
+ GSAP is **not** loaded there. It comes from Webflow's native Site Settings
35
+ toggle (3.15.0 with SplitText); a second copy would register ScrollTrigger twice.
48
36
 
49
- ```js
50
- localStorage.setItem('shopic-dev', 'on'); // off: localStorage.removeItem('shopic-dev')
51
- ```
37
+ ## Seeing a change on the site
38
+
39
+ Publish it. There is no localhost preview.
52
40
 
53
- Without that gate every visitor's browser would probe your localhost. With it,
54
- only yours does, and it falls back to the CDN the moment `pnpm dev` is not running.
41
+ ```bash
42
+ pnpm check && pnpm lint && pnpm build
43
+ npm version patch --no-git-tag-version
44
+ git add -A && git commit -m "…" && git push
45
+ npm publish # needs the 2FA passkey
46
+ ```
55
47
 
56
- Two things to know: Chrome and Firefox allow `http://localhost` from an HTTPS page,
57
- **Safari blocks it** work in Chrome. And the dev URL has no `/dist` in it, because
58
- esbuild serves that directory as the root (`src/pages/home.ts` → `/pages/home.js`).
48
+ Then bump the version in the footer snippet and reload the site. jsDelivr serves
49
+ a new version within a minute or so.
50
+
51
+ ### Why there is no localhost preview
52
+
53
+ The obvious setup — footer script pointing at `http://localhost:3000` behind a
54
+ localStorage flag — does not work from a published Webflow page, and cannot be
55
+ made to work without dismantling browser protections. Established by measurement
56
+ on 2026-09-01, in this order:
57
+
58
+ 1. **Mixed content.** An http subresource on an https page is blocked. Silently:
59
+ the script tag is in the DOM, the request never completes, nothing is logged.
60
+ It looks exactly like a bundle that loaded and did nothing.
61
+ 2. **Private Network Access.** Clearing the first one only reveals this:
62
+ `Permission was denied for this request to access the loopback address space`.
63
+ esbuild's server cannot opt in — it answers OPTIONS with a 404 and never sends
64
+ `Access-Control-Allow-Private-Network`.
65
+ 3. **Local Network Access.** Sending those headers from a proxy is still not
66
+ enough. Chrome now requires the *user* to grant permission before any site
67
+ reaches a loopback address, and a `<script src>` cannot request it —
68
+ `targetAddressSpace` is a `fetch()` option, so it would mean fetching the code
69
+ and injecting it by hand.
70
+
71
+ Each of those exists to stop a public page from reaching services on the
72
+ visitor's machine. Getting a preview would mean a browser flag, plus a proxy,
73
+ plus a granted permission — three mitigations bypassed so that a reload is
74
+ faster.
75
+
76
+ Two other routes were tried and rejected:
77
+
78
+ - **A local TLS certificate (`mkcert`).** Solves step 1, but `mkcert -install`
79
+ puts a private CA in the system trust store, and whoever reads that CA's key
80
+ can mint a certificate for *any* domain that the browser accepts without
81
+ warning. Permanent, machine-wide exposure for a development convenience.
82
+ - **A Chrome flag on a throwaway profile.** Also solves step 1, but stops at
83
+ step 3.
84
+
85
+ **Do not reopen this.** If a preview loop becomes genuinely necessary, the answer
86
+ is a local page that loads the bundle over plain http from a plain http page —
87
+ not a way to make the published site reach this machine.
59
88
 
60
89
  ## Releasing
61
90
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";(()=>{var c=new Map;var i=(e,t=document)=>{let p=t.querySelectorAll("[data-anim]");for(let o of p){let r=o.dataset.anim;if(!r)continue;let n=c.get(r);if(!n){console.warn(`[shopic] No animation registered for data-anim="${r}".`,o);continue}n(o,e)}};var a=()=>{let{gsap:e,ScrollTrigger:t}=window;if(!e)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return t&&e.registerPlugin(t),{gsap:e,ScrollTrigger:t}},s=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:e,ScrollTrigger:t}=a();i({gsap:e,ScrollTrigger:t,reducedMotion:s()})});})();
1
+ "use strict";(()=>{var M=new Map,f=(e,n)=>{if(M.has(e))throw new Error(`[shopic] Animation "${e}" is registered twice.`);M.set(e,n)},C=(e,n=document)=>{let r=n.querySelectorAll("[data-anim]");for(let t of r){let l=t.dataset.anim;if(!l||t.dataset.animState==="ready")continue;let a=M.get(l);if(!a){console.warn(`[shopic] No animation registered for data-anim="${l}".`,t);continue}t.dataset.animState="ready",a(t,e)}};var $=2,F=150,U=[0,.25,.5,.6,.7,.8,.9,1],x="shopic:slide-enter";f("carousel",(e,{reducedMotion:n})=>{let r=Array.from(e.querySelectorAll(":scope > [data-slide]"));if(r.length<2)return;let t=e.closest("section")??e.parentElement??document.body,l=Array.from(t.querySelectorAll("[data-tab]")),a=n?"auto":"smooth",s=o=>o.getBoundingClientRect().left-e.getBoundingClientRect().left+e.scrollLeft,d=()=>parseFloat(getComputedStyle(e).paddingLeft)||0,i=(o,c)=>{e.scrollTo({left:s(o)-d(),behavior:c?a:"auto"})},m=r[r.length-1].cloneNode(!0),g=r[0].cloneNode(!0);for(let o of[m,g]){o.dataset.slideClone="true",o.setAttribute("aria-hidden","true");for(let c of o.querySelectorAll("[data-anim]"))c.dataset.animState="ready"}e.insertBefore(m,r[0]),e.append(g);let L=Array.from(e.querySelectorAll(":scope > [data-slide]")),A=o=>{for(let c of l)c.classList.toggle("is-active",c.dataset.tab===o)};for(let o of l)o.addEventListener("click",c=>{c.preventDefault();let T=o.dataset.tab,y=r.find(u=>u.dataset.slide===T);y&&i(y,!0)});let S=new Map(L.map(o=>[o,0])),p=null,b=new IntersectionObserver(o=>{for(let u of o)S.set(u.target,u.isIntersecting?u.intersectionRatio:0);let c=null,T=0;for(let u of L){let N=S.get(u)??0;N>T&&(T=N,c=u)}if(!c)return;let y=c.dataset.slide;y&&A(y);for(let u of L)u.classList.toggle("is-current",u===c);c!==p&&(p=c,c.dispatchEvent(new CustomEvent(x)))},{root:e,threshold:U});for(let o of L)b.observe(o);e.scrollLeft=s(r[0])-d();let h=()=>{let o=null,c=1/0;for(let T of L){let y=Math.abs(s(T)-d()-e.scrollLeft);y<c&&(c=y,o=T)}return o},w=()=>{let o=h();if(!o?.dataset.slideClone)return;let c=r.find(T=>T.dataset.slide===o.dataset.slide);c&&(e.style.scrollSnapType="none",e.scrollLeft-=s(o)-s(c),e.offsetHeight,e.style.scrollSnapType="")};if("onscrollend"in window)e.addEventListener("scrollend",w);else{let o;e.addEventListener("scroll",()=>{clearTimeout(o),o=setTimeout(w,F)})}let E=!1,H=0,I=0;e.addEventListener("pointerdown",o=>{E=!0,e.classList.add("is-dragging"),H=o.clientX,I=e.scrollLeft}),window.addEventListener("pointermove",o=>{E&&(e.scrollLeft=I-(o.clientX-H)*$)}),window.addEventListener("pointerup",()=>{if(!E)return;E=!1,e.classList.remove("is-dragging");let o=h();o&&i(o,!0)})});var R="!<>-_\\/[]{}=+*^?#$%01",O=new WeakMap,v=(e,{duration:n=1050,stagger:r=.75,text:t,reducedMotion:l=!1}={})=>{if(l){t!==void 0&&(e.textContent=t);return}if(t!==void 0)e.dataset.scrambleText=t;else if(!e.dataset.scrambleText){let p=e.textContent;if(!p||!p.trim())return;e.dataset.scrambleText=p}let a=e.dataset.scrambleText;if(!a||!a.trim())return;let s=Array.from(a),d=s.length;e.textContent="";let i=document.createDocumentFragment(),m=s.map(p=>{let b=document.createElement("span");return b.textContent=p,i.append(b),b});e.append(i);let g=Symbol("scramble");O.set(e,g);let L=s.map((p,b)=>d<=1?0:b/(d-1)*n*r),A=performance.now(),S=p=>{if(O.get(e)!==g)return;let b=p-A,h=!0;s.forEach((w,E)=>{w!==" "&&(b>=L[E]?m[E].textContent=w:(h=!1,m[E].textContent=R[Math.random()*R.length|0]))}),h||requestAnimationFrame(S)};requestAnimationFrame(S)},_=(e,n={})=>{e.dataset.scrambleHoverBound||(e.dataset.scrambleHoverBound="true",e.addEventListener("pointerenter",()=>v(e,n)))};var X=.5,V="power2.out",j=".status-pill, .evidence_label, .evidence_sku";f("evidence",(e,{gsap:n,reducedMotion:r})=>{let t=Array.from(e.children);if(!t.length)return;if(r){for(let i of t)i.style.height="auto",i.style.opacity="1";return}let l=()=>{n.killTweensOf(t),n.set(t,{height:0,opacity:0,overflow:"hidden"});let i=n.timeline();for(let m of t)i.call(()=>{for(let g of m.querySelectorAll(j))v(g,{duration:630,stagger:.6})}),i.to(m,{height:"auto",opacity:1,duration:X,ease:V,onComplete:()=>n.set(m,{height:"auto"})})},a=!1,s=!1,d=()=>{if(!a)return;let i=e.closest("[data-slide]");i&&!i.classList.contains("is-current")||(s=!0,l())};if("IntersectionObserver"in window){let i=new IntersectionObserver(m=>{for(let g of m)g.isIntersecting&&(a=!0,d(),s&&i.disconnect())},{threshold:.2});i.observe(e)}else a=!0,d();e.closest("[data-slide]")?.addEventListener(x,d)});var D="split_line",z="split_word",G="split_word-inner",J=e=>{let n=document.createDocumentFragment(),r=[],t=document.createElement("span");t.className=D,n.appendChild(t);let l=(s,d)=>{if(!s)return;let i=document.createElement("span");i.className=z;let m=document.createElement("span");m.className=d?`${G} ${d}`:G,m.textContent=s,i.appendChild(m),t.appendChild(i),r.push(m)},a=(s,d)=>{for(let i of s.split(/(\s+)/))i&&(/^\s+$/.test(i)?t.appendChild(document.createTextNode(" ")):l(i,d))};for(let s of Array.from(e.childNodes))s.nodeType===Node.TEXT_NODE?a(s.textContent??""):s instanceof HTMLBRElement?(t=document.createElement("span"),t.className=D,n.appendChild(t)):s instanceof HTMLElement&&a(s.textContent??"",s.className||void 0);return e.textContent="",e.appendChild(n),r},q={yPercent:0,duration:.9,ease:"power4.out",stagger:.035};f("headline",(e,{gsap:n,ScrollTrigger:r,reducedMotion:t})=>{if(t){e.style.visibility="visible";return}let l=J(e);if(n.set(l,{yPercent:110}),e.style.visibility="visible",e.dataset.animTrigger==="load"||!r){n.to(l,{...q,delay:.3});return}n.to(l,{...q,scrollTrigger:{trigger:e,start:"top 85%"}})});var K=26;f("marquee",(e,{gsap:n,reducedMotion:r})=>{if(r)return;let t=Number(e.dataset.animSets??4),l=Number(e.dataset.animDuration??K);if(!Number.isFinite(t)||t<2)return;let a=()=>e.scrollWidth/t,s=n.to(e,{x:()=>-a(),duration:l,ease:"none",repeat:-1,modifiers:{x:i=>`${Number.parseFloat(i)%a()}px`}}),d=e.parentElement;d&&(d.addEventListener("pointerenter",()=>s.pause()),d.addEventListener("pointerleave",()=>s.resume()))});var B="is-visible";f("reveal",(e,{reducedMotion:n})=>{let r=Number(e.dataset.animDelay??0);if(r&&(e.style.transitionDelay=`${r}ms`),n||!("IntersectionObserver"in window)){e.classList.add(B);return}let t=new IntersectionObserver(l=>{for(let a of l)a.isIntersecting&&(a.target.classList.add(B),t.unobserve(a.target))},{threshold:.15});t.observe(e)});f("scramble",(e,{reducedMotion:n})=>{let r={duration:Number(e.dataset.animDuration??1050),stagger:Number(e.dataset.animStagger??.75),reducedMotion:n};if(n||!("IntersectionObserver"in window)){v(e,r);return}let t=new IntersectionObserver(l=>{for(let a of l)a.isIntersecting&&(v(e,r),_(e,r),t.unobserve(a.target))},{threshold:.2});t.observe(e)});var P=()=>{let{gsap:e,ScrollTrigger:n}=window;if(!e)throw new Error("[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.");return n&&e.registerPlugin(n),{gsap:e,ScrollTrigger:n}},W=()=>window.matchMedia("(prefers-reduced-motion: reduce)").matches;window.Webflow||(window.Webflow=[]);window.Webflow.push(()=>{let{gsap:e,ScrollTrigger:n}=P();C({gsap:e,ScrollTrigger:n,reducedMotion:W()})});})();
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../bin/live-reload.js", "../src/anim/registry.ts", "../src/anim/headline.ts", "../src/anim/marquee.ts", "../src/anim/reveal.ts", "../src/lib/gsap.ts", "../src/index.ts"],
4
+ "sourcesContent": ["new EventSource(`${SERVE_ORIGIN}/esbuild`).addEventListener('change', () => location.reload());\n", "import type { Gsap, ScrollTriggerType } from '$lib/gsap';\n\nexport type AnimationContext = {\n gsap: Gsap;\n ScrollTrigger?: ScrollTriggerType;\n reducedMotion: boolean;\n};\n\nexport type AnimationInit = (element: HTMLElement, context: AnimationContext) => void;\n\nconst registry = new Map<string, AnimationInit>();\n\n/**\n * Registers an animation under the name used in `data-anim`.\n * The client edits content in the Designer; the attribute is the only contract\n * between their markup and this bundle.\n */\nexport const registerAnimation = (name: string, init: AnimationInit): void => {\n if (registry.has(name)) {\n throw new Error(`[shopic] Animation \"${name}\" is registered twice.`);\n }\n\n registry.set(name, init);\n};\n\n/**\n * Runs every registered animation against the elements that ask for it.\n * Unknown names warn rather than throw \u2014 a stray attribute in the Designer\n * must not take the whole bundle down.\n *\n * Initialisation is once per element, and the marker lives on the element\n * rather than in module scope so that a *second copy* of this bundle sees it\n * too. That is not hypothetical: a stale inlined copy alongside the CDN one\n * re-split an already-split headline, and because the splitter carries a\n * parent's className onto the words it produces, every word inherited\n * `split_line` (display: block) and stacked one per line.\n */\nexport const runAnimations = (context: AnimationContext, root: ParentNode = document): void => {\n const elements = root.querySelectorAll<HTMLElement>('[data-anim]');\n\n for (const element of elements) {\n const name = element.dataset.anim;\n if (!name) continue;\n if (element.dataset.animState === 'ready') continue;\n\n const init = registry.get(name);\n\n if (!init) {\n // eslint-disable-next-line no-console\n console.warn(`[shopic] No animation registered for data-anim=\"${name}\".`, element);\n continue;\n }\n\n element.dataset.animState = 'ready';\n init(element, context);\n }\n};\n", "import { registerAnimation } from './registry';\n\nconst LINE = 'split_line';\nconst WORD = 'split_word';\nconst INNER = 'split_word-inner';\n\n/**\n * Wraps every word in an overflow-hidden span so it can slide up into view.\n * `<br>` starts a new line; existing child spans (accent colours) survive as\n * single words and keep their class. The class names are real Webflow styles \u2014\n * a class that only ever exists at runtime gets stripped from the published CSS.\n */\nconst splitHeadline = (element: HTMLElement): HTMLElement[] => {\n const fragment = document.createDocumentFragment();\n const words: HTMLElement[] = [];\n let line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n\n const addWord = (text: string, className?: string): void => {\n if (!text) return;\n\n const outer = document.createElement('span');\n outer.className = WORD;\n\n const inner = document.createElement('span');\n inner.className = className ? `${INNER} ${className}` : INNER;\n inner.textContent = text;\n\n outer.appendChild(inner);\n line.appendChild(outer);\n words.push(inner);\n };\n\n const addChunks = (text: string, className?: string): void => {\n for (const chunk of text.split(/(\\s+)/)) {\n if (!chunk) continue;\n if (/^\\s+$/.test(chunk)) line.appendChild(document.createTextNode(' '));\n else addWord(chunk, className);\n }\n };\n\n for (const node of Array.from(element.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n addChunks(node.textContent ?? '');\n } else if (node instanceof HTMLBRElement) {\n line = document.createElement('span');\n line.className = LINE;\n fragment.appendChild(line);\n } else if (node instanceof HTMLElement) {\n addChunks(node.textContent ?? '', node.className || undefined);\n }\n }\n\n element.textContent = '';\n element.appendChild(fragment);\n\n return words;\n};\n\nconst TWEEN = { yPercent: 0, duration: 0.9, ease: 'power4.out', stagger: 0.035 } as const;\n\nregisterAnimation('headline', (element, { gsap, ScrollTrigger, reducedMotion }) => {\n if (reducedMotion) {\n element.style.visibility = 'visible';\n return;\n }\n\n const words = splitHeadline(element);\n gsap.set(words, { yPercent: 110 });\n element.style.visibility = 'visible';\n\n // The hero headline is above the fold, so it plays on load; everything else\n // waits for the scroll to reach it.\n if (element.dataset.animTrigger === 'load' || !ScrollTrigger) {\n gsap.to(words, { ...TWEEN, delay: 0.3 });\n return;\n }\n\n gsap.to(words, { ...TWEEN, scrollTrigger: { trigger: element, start: 'top 85%' } });\n});\n", "import { registerAnimation } from './registry';\n\nconst DEFAULT_DURATION = 26;\n\n/**\n * Infinite logo strip. The track holds the same set of logos repeated N times,\n * so translating by exactly one set's width lands on an identical frame \u2014 no\n * measuring loop, no drift. N comes from the DOM, not a constant, so adding a\n * logo in the Designer cannot desync the loop.\n */\nregisterAnimation('marquee', (element, { gsap, reducedMotion }) => {\n if (reducedMotion) return;\n\n const sets = Number(element.dataset.animSets ?? 4);\n const duration = Number(element.dataset.animDuration ?? DEFAULT_DURATION);\n if (!Number.isFinite(sets) || sets < 2) return;\n\n const distance = () => element.scrollWidth / sets;\n\n const tween = gsap.to(element, {\n x: () => -distance(),\n duration,\n ease: 'none',\n repeat: -1,\n modifiers: {\n // wrap inside one set so the tween never accumulates a huge offset\n x: (value: string) => `${Number.parseFloat(value) % distance()}px`,\n },\n });\n\n const parent = element.parentElement;\n if (!parent) return;\n\n parent.addEventListener('pointerenter', () => tween.pause());\n parent.addEventListener('pointerleave', () => tween.resume());\n});\n", "import { registerAnimation } from './registry';\n\nconst VISIBLE = 'is-visible';\n\n/**\n * Fade-and-rise on entry. The motion itself is a CSS transition on\n * `.hero_media`; this only decides when to add the state class, so the\n * client can restyle the easing in the Designer without touching the bundle.\n */\nregisterAnimation('reveal', (element, { reducedMotion }) => {\n const delay = Number(element.dataset.animDelay ?? 0);\n if (delay) element.style.transitionDelay = `${delay}ms`;\n\n if (reducedMotion || !('IntersectionObserver' in window)) {\n element.classList.add(VISIBLE);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n entry.target.classList.add(VISIBLE);\n observer.unobserve(entry.target);\n }\n },\n { threshold: 0.15 }\n );\n\n observer.observe(element);\n});\n", "import type { gsap as GsapStatic } from 'gsap';\nimport type { ScrollTrigger as ScrollTriggerStatic } from 'gsap/ScrollTrigger';\n\ndeclare global {\n interface Window {\n gsap?: typeof GsapStatic;\n ScrollTrigger?: typeof ScrollTriggerStatic;\n }\n}\n\nexport type Gsap = typeof GsapStatic;\nexport type ScrollTriggerType = typeof ScrollTriggerStatic;\n\n/**\n * GSAP ships from Webflow's native Site Settings toggle, not from this bundle.\n * A site transfer wipes Site Settings, so the toggle can silently disappear and\n * take every animation with it. Fail loudly here instead.\n */\nexport const requireGsap = (): { gsap: Gsap; ScrollTrigger?: ScrollTriggerType } => {\n const { gsap, ScrollTrigger } = window;\n\n if (!gsap) {\n throw new Error(\n '[shopic] GSAP is not on the page. Enable it in Webflow \u2192 Site Settings \u2192 Custom Code \u2192 GSAP.'\n );\n }\n\n if (ScrollTrigger) gsap.registerPlugin(ScrollTrigger);\n\n return { gsap, ScrollTrigger };\n};\n\n/**\n * Whether the visitor asked the OS to cut down on motion.\n */\nexport const prefersReducedMotion = (): boolean =>\n window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n", "import { runAnimations } from '$anim/index';\nimport { prefersReducedMotion, requireGsap } from '$lib/gsap';\n\nwindow.Webflow ||= [];\nwindow.Webflow.push(() => {\n const { gsap, ScrollTrigger } = requireGsap();\n\n runAnimations({ gsap, ScrollTrigger, reducedMotion: prefersReducedMotion() });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopic",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Custom code bundle for the Shopic Webflow site.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,