diff --git a/toonz/sources/include/tools/assistant.h b/toonz/sources/include/tools/assistant.h
index e915737..f79377a 100644
--- a/toonz/sources/include/tools/assistant.h
+++ b/toonz/sources/include/tools/assistant.h
@@ -326,6 +326,10 @@ protected:
   inline void drawDot(const TPointD &p) const
     { drawDot(p, getDrawingAlpha()); }
 
+  TIntProperty* createSpinProperty(const TStringId &id, int def, int min, int max, bool hasMax = true);
+  inline TIntProperty* createSpinProperty(const TStringId &id, int def, int min)
+    { return createSpinProperty(id, def, min, 0, false); }
+  
   void addProperty(TProperty *p);
   void setTranslation(const TStringId &name, const QString &localName) const;
 
diff --git a/toonz/sources/include/tools/modifiers/modifierjitter.h b/toonz/sources/include/tools/modifiers/modifierjitter.h
new file mode 100644
index 0000000..2f048e4
--- /dev/null
+++ b/toonz/sources/include/tools/modifiers/modifierjitter.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#ifndef MODIFIERJITTER_INCLUDED
+#define MODIFIERJITTER_INCLUDED
+
+// TnzTools includes
+#include <tools/inputmanager.h>
+
+#undef DVAPI
+#undef DVVAR
+#ifdef TNZTOOLS_EXPORTS
+#define DVAPI DV_EXPORT_API
+#define DVVAR DV_EXPORT_VAR
+#else
+#define DVAPI DV_IMPORT_API
+#define DVVAR DV_IMPORT_VAR
+#endif
+
+//===================================================================
+
+//*****************************************************************************************
+//    TModifierJitter definition
+//*****************************************************************************************
+
+class DVAPI TModifierJitter : public TInputModifier {
+public:
+  typedef TSubTrackHandler Handler;
+
+  class DVAPI Interpolator : public TTrackInterpolator {
+  public:
+    const unsigned int seedX;
+    const unsigned int seedY;
+    const double frequency;
+    const double amplitude;
+    Interpolator(TTrack &track, double period, double amplitude);
+    TTrackPoint interpolateFromOriginal(double originalIndex);
+    TTrackPoint interpolate(double index) override;
+  };
+
+public:
+  double period;
+  double amplitude;
+  int skipFirst;
+  
+  TModifierJitter(
+    double period = 30,
+    double amplitude = 10,
+    int skipFirst = 0 );
+
+  void modifyTrack(
+    const TTrack &track,
+    TTrackList &outTracks ) override;
+  
+  void modifyTracks(
+    const TTrackList &tracks,
+    TTrackList &outTracks ) override;
+  
+  static double func(unsigned int seed, double x);
+};
+
+#endif
diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt
index 368aa99..1518eee 100644
--- a/toonz/sources/tnztools/CMakeLists.txt
+++ b/toonz/sources/tnztools/CMakeLists.txt
@@ -52,6 +52,7 @@ set(HEADERS
     ../include/tools/replicator.h
     ../include/tools/modifiers/modifierassistants.h
     ../include/tools/modifiers/modifierclone.h
+    ../include/tools/modifiers/modifierjitter.h
     ../include/tools/modifiers/modifierline.h
     ../include/tools/modifiers/modifiersegmentation.h
     ../include/tools/modifiers/modifiersimplify.h
@@ -131,6 +132,7 @@ set(SOURCES
     replicator.cpp
     modifiers/modifierassistants.cpp
     modifiers/modifierclone.cpp
+    modifiers/modifierjitter.cpp
     modifiers/modifierline.cpp
     modifiers/modifiersegmentation.cpp
     modifiers/modifiersimplify.cpp
@@ -144,6 +146,7 @@ set(SOURCES
     assistants/assistantellipse.cpp
     assistants/replicatoraffine.cpp
     assistants/replicatorgrid.cpp
+    assistants/replicatorjitter.cpp
     assistants/replicatormirror.cpp
     assistants/replicatorstar.cpp
     editassistantstool.cpp
diff --git a/toonz/sources/tnztools/assistant.cpp b/toonz/sources/tnztools/assistant.cpp
index b7c37f1..a342f5e 100644
--- a/toonz/sources/tnztools/assistant.cpp
+++ b/toonz/sources/tnztools/assistant.cpp
@@ -202,6 +202,17 @@ TAssistantBase::getBasePoint() const
 
 //---------------------------------------------------------------------------------------------------
 
+TIntProperty*
+TAssistantBase::createSpinProperty(const TStringId &id, int def, int min, int max, bool hasMax) {
+  if (!hasMax && max < def) max = def;
+  assert(min <= def && def <= max);
+  TIntProperty *property = new TIntProperty(id.str(), min, max, def, hasMax);
+  property->setSpinner();
+  return property;
+}
+
+//---------------------------------------------------------------------------------------------------
+
 void
 TAssistantBase::addProperty(TProperty *p)
   { m_properties.add(p); }
diff --git a/toonz/sources/tnztools/assistants/replicatorjitter.cpp b/toonz/sources/tnztools/assistants/replicatorjitter.cpp
new file mode 100644
index 0000000..befb329
--- /dev/null
+++ b/toonz/sources/tnztools/assistants/replicatorjitter.cpp
@@ -0,0 +1,149 @@
+
+
+// TnzTools includes
+#include <tools/replicator.h>
+#include <tools/modifiers/modifierjitter.h>
+
+
+// TnzCore includes
+#include <tgl.h>
+
+
+//*****************************************************************************************
+//    TReplicatorJitter implementation
+//*****************************************************************************************
+
+class TReplicatorJitter final : public TReplicator {
+  Q_DECLARE_TR_FUNCTIONS(TReplicatorJitter)
+public:
+  const TStringId m_idSkipFirst;
+  const TStringId m_idPeriod;
+  const TStringId m_idAmplitude;
+
+protected:
+  TAssistantPoint &m_center;
+
+public:
+  TReplicatorJitter(TMetaObject &object):
+    TReplicator(object),
+    m_idSkipFirst("skipFirst"),
+    m_idPeriod("period"),
+    m_idAmplitude("m_idAmplitude"),
+    m_center( addPoint("center", TAssistantPoint::CircleCross) )
+  {
+    addProperty( createSpinProperty(m_idSkipFirst, getSkipFirst(), 0) );
+
+    TDoubleProperty *p;
+    
+    p = new TDoubleProperty(m_idPeriod.str(), 0.0, 1000, getPeriod());
+    p->setNonLinearSlider();
+    addProperty(p);
+
+    p = new TDoubleProperty(m_idAmplitude.str(), 0.0, 1000, getAmplitude());
+    p->setNonLinearSlider();
+    addProperty(p);
+  }
+
+  
+  static QString getLocalName()
+    { return tr("Jitter"); }
+
+    
+  void updateTranslation() const override {
+    TReplicator::updateTranslation();
+    setTranslation(m_idSkipFirst, tr("Skip First Tracks"));
+    setTranslation(m_idPeriod, tr("Period"));
+    setTranslation(m_idAmplitude, tr("Amplitude"));
+  }
+
+  
+  inline int getSkipFirst() const
+    { return (int)data()[m_idSkipFirst].getDouble(); }
+  inline double getPeriod() const
+    { return data()[m_idPeriod].getDouble(); }
+  inline double getAmplitude() const
+    { return data()[m_idAmplitude].getDouble(); }
+
+protected:
+  inline void setSkipFirst(int x)
+    { if (getSkipFirst() != (double)x) data()[m_idSkipFirst].setDouble((double)x); }
+  inline void setPeriod(double x)
+    { if (getPeriod() != x) data()[m_idPeriod].setDouble(x); }
+  inline void setAmplitude(double x)
+    { if (getAmplitude() != x) data()[m_idAmplitude].setDouble(x); }
+
+    
+  void onSetDefaults() override {
+    setPeriod(30);
+    setAmplitude(10);
+    TReplicator::onSetDefaults();
+  }
+
+  
+  void onFixData() override {
+    TReplicator::onFixData();
+    setPeriod( std::max(0.0, std::min(1000.0, getPeriod())) );
+    setAmplitude( std::max(0.0, std::min(1000.0, getAmplitude())) );
+  }
+
+  
+  double getScale(const TAffine &a) const {
+    return sqrt( a.a11*a.a11 + a.a12*a.a12
+               + a.a21*a.a21 + a.a22*a.a22 )/2;
+  }
+    
+public:
+  
+  void getPoints(const TAffine &toTool, PointList &points) const override {
+    int skipFirst = getSkipFirst();
+    if (skipFirst < 0) skipFirst = 0;
+    if (skipFirst >= (int)points.size()) return;
+    
+    double scale = getScale(toTool);
+    double period = getPeriod()*scale;
+    double amplitude = getAmplitude()*scale;
+    if (!(period > TConsts::epsilon && amplitude > TConsts::epsilon)) {
+      int seedX = 0;
+      int seedY = 7722441;
+      for(PointList::iterator i = points.begin() + skipFirst; i != points.end(); ++i) {
+        i->x += TModifierJitter::func(seedX, 0)*amplitude;
+        i->y += TModifierJitter::func(seedY, 0)*amplitude;
+        ++seedX, ++seedY;
+      }
+    }
+  }
+  
+  
+  void getModifiers(
+    const TAffine &toTool,
+    TInputModifier::List &outModifiers ) const override
+  {
+    double scale = getScale(toTool);
+    outModifiers.push_back(new TModifierJitter(
+      getPeriod()*scale,
+      getAmplitude()*scale,
+      getSkipFirst() ));
+  }
+
+  
+  void draw(TToolViewer*, bool enabled) const override {
+    double alpha = getDrawingAlpha(enabled);
+    double pixelSize = sqrt(tglGetPixelSize2());
+    
+    TPointD c = m_center.position;
+    double h = getPeriod()/2;
+    double q = h/2;
+    double a = getAmplitude();
+    
+    drawSegment(TPointD(c.x-h, c.y  ), TPointD(c.x-q, c.y+a), pixelSize, alpha);
+    drawSegment(TPointD(c.x-q, c.y+a), TPointD(c.x+q, c.y-a), pixelSize, alpha);
+    drawSegment(TPointD(c.x+q, c.y-a), TPointD(c.x+h, c.y  ), pixelSize, alpha);
+  }
+};
+
+
+//*****************************************************************************************
+//    Registration
+//*****************************************************************************************
+
+static TAssistantTypeT<TReplicatorJitter> replicatorJitter("replicatorJitter");
diff --git a/toonz/sources/tnztools/assistants/replicatormirror.cpp b/toonz/sources/tnztools/assistants/replicatormirror.cpp
index 0fca92d..0c608c8 100644
--- a/toonz/sources/tnztools/assistants/replicatormirror.cpp
+++ b/toonz/sources/tnztools/assistants/replicatormirror.cpp
@@ -30,7 +30,7 @@ public:
     m_idDiscreteAngle("discreteAngle"),
     m_idPressure("pressure"),
     m_a( addPoint("a", TAssistantPoint::CircleCross) ),
-    m_b( addPoint("b", TAssistantPoint::Circle, TPointD(50, 0)) )
+    m_b( addPoint("b", TAssistantPoint::Circle, TPointD(0, -50)) )
   {
     addProperty( new TBoolProperty(m_idDiscreteAngle.str(),  getDiscreteAngle()) );
     addProperty( new TDoubleProperty(m_idPressure.str(), 0.0, 2.0, getPressure()) );
diff --git a/toonz/sources/tnztools/modifiers/modifierjitter.cpp b/toonz/sources/tnztools/modifiers/modifierjitter.cpp
new file mode 100644
index 0000000..292bb82
--- /dev/null
+++ b/toonz/sources/tnztools/modifiers/modifierjitter.cpp
@@ -0,0 +1,172 @@
+
+#include <tools/modifiers/modifierjitter.h>
+
+
+
+//*****************************************************************************************
+//    static functions
+//*****************************************************************************************
+
+
+namespace {
+
+class Jitter {
+public:
+  static inline double randomNext(unsigned int &seed) {
+    static const unsigned int max = 32767;
+    static const double k = 1.0/max;
+    seed = ((1103515245*seed + 12345) >> 16) & max;
+    return seed*k;
+  }
+
+  static TPointD getPoint(unsigned int seed, int i, double *prevX = nullptr) {
+    unsigned int pseed = seed^i;
+    double dx = randomNext(pseed);
+    double dy = randomNext(pseed)*2 - 1;
+    if (dx < 0.5) {
+      double px = prevX ? *prevX : getPoint(seed, i-1).x;
+      px += 0.5 - i;
+      if (dx < px)
+        dx = randomNext(pseed)*(1 - px) + px;
+    }
+    return TPointD(dx + i, dy);
+  }
+
+  static inline double spline(double x, TPointD *points) {
+    double x0 = points[1].x;
+    double y0 = points[1].y;
+    double x1 = points[2].x;
+    double y1 = points[2].y;
+    double t0 = (y1 - points[0].y)/(x1 - points[0].x)*(x1 - x0);
+    double t1 = (points[3].y - y0)/(points[3].x - x0)*(x1 - x0);
+
+    double l = (x - x0)/(x1 - x0);
+    double ll = l*l;
+    double lll = ll*l;
+
+    return y0*( 2*lll - 3*ll + 1)
+         + y1*(-2*lll + 3*ll    )
+         + t0*(   lll - 2*ll + l)
+         + t1*(   lll -   ll    );
+  }
+
+  static inline double func(unsigned int seed, double x) {
+    int i = (int)floor(x);
+    TPointD points[5];
+    points[0] = getPoint(seed, i-2);
+    for(int j = 1; j < 5; ++j)
+      points[j] = getPoint(seed, i-2+j, &points[j-1].x);
+    return spline(x, &points[ x < points[2].x ? 0 : 1 ]);
+  }
+};
+
+static inline unsigned int trackSeedX(const TTrack &track) {
+  unsigned int seed = track.id;
+  Jitter::randomNext(seed);
+  return seed;
+}
+
+static inline unsigned int trackSeedY(const TTrack &track) {
+  unsigned int seed = track.id^32143;
+  Jitter::randomNext(seed);
+  return seed;
+}
+
+} // namespace
+
+
+
+//*****************************************************************************************
+//    TModifierJitter::Interpolator implementation
+//*****************************************************************************************
+
+
+TModifierJitter::Interpolator::Interpolator(TTrack &track, double period, double amplitude):
+  TTrackInterpolator(track),
+  seedX(trackSeedX(track)),
+  seedY(trackSeedY(track)),
+  frequency(fabs(period) > TConsts::epsilon ? 1/period : 0),
+  amplitude(fabs(period) > TConsts::epsilon ? amplitude : 0)
+  { }
+
+
+TTrackPoint TModifierJitter::Interpolator::interpolateFromOriginal(double originalIndex) {
+  TTrackPoint p = track.calcPointFromOriginal(originalIndex);
+  double l = p.length*frequency;
+  p.position.x += Jitter::func(seedX, l)*amplitude;
+  p.position.y += Jitter::func(seedY, l)*amplitude;
+  return p;
+}
+
+
+TTrackPoint TModifierJitter::Interpolator::interpolate(double index)
+  { return interpolateFromOriginal(track.originalIndexByIndex(index)); }
+
+
+ 
+//*****************************************************************************************
+//    TModifierJitter implementation
+//*****************************************************************************************
+
+
+TModifierJitter::TModifierJitter(double period, double amplitude, int skipFirst):
+  period(period), amplitude(amplitude), skipFirst(skipFirst) { }
+
+
+void TModifierJitter::modifyTrack(const TTrack &track,
+                                  TTrackList &outTracks)
+{
+  if (!track.handler && fabs(period) > TConsts::epsilon) {
+    Handler *handler = new Handler();
+    track.handler = handler;
+    handler->track = new TTrack(track);
+    new Interpolator(*handler->track, period, amplitude);
+  }
+  
+  Handler *handler = dynamic_cast<Handler*>(track.handler.getPointer());
+  if (!handler)
+    return TInputModifier::modifyTrack(track, outTracks);
+  
+  outTracks.push_back(handler->track);
+  TTrack &subTrack = *handler->track;
+  
+  if (!track.changed())
+    return;
+
+  Interpolator *intr = dynamic_cast<Interpolator*>(subTrack.getInterpolator().getPointer());
+  if (!intr)
+    return;
+
+  int start = track.size() - track.pointsAdded;
+  if (start < 0) start = 0;
+
+  // process sub-track
+  subTrack.truncate(start);
+  for (int i = start; i < track.size(); ++i)
+    subTrack.push_back(intr->interpolateFromOriginal(i), false);
+  
+  // fit points
+  subTrack.fix_to(track.fixedSize());
+  
+  track.resetChanges();
+}
+
+
+void
+TModifierJitter::modifyTracks(
+    const TTrackList &tracks,
+    TTrackList &outTracks )
+{
+  int cnt = std::min( std::max(0, skipFirst), (int)tracks.size() );
+  TTrackList::const_iterator split = tracks.begin() + cnt;
+  for(TTrackList::const_iterator i = tracks.begin(); i != split; ++i)
+    TInputModifier::modifyTrack(**i, outTracks);
+  for(TTrackList::const_iterator i = split; i != tracks.end(); ++i)
+    modifyTrack(**i, outTracks);
+}
+
+
+double TModifierJitter::func(unsigned int seed, double x)
+  { return Jitter::func(seed, x); }
+
+  
diff --git a/toonz/sources/tnztools/replicator.cpp b/toonz/sources/tnztools/replicator.cpp
index 1699928..6e63cb6 100644
--- a/toonz/sources/tnztools/replicator.cpp
+++ b/toonz/sources/tnztools/replicator.cpp
@@ -51,10 +51,7 @@ TReplicator::createCountProperty(const TStringId &id, int def, int min, int max)
   if (min < 0) min = 0;
   if (def < min) def = min;
   if (max <= 0) max = multiplierSoftLimit;
-  assert(min < max && def < max);
-  TIntProperty *property = new TIntProperty(id.str(), min, max, def);
-  property->setSpinner();
-  return property;
+  return createSpinProperty(id, def, min, max);
 }
 
 //---------------------------------------------------------------------------------------------------